UNPKG

angularplasmid

Version:

Biological Plasmid Visualization Component using AngularJS

1,045 lines (926 loc) 54 kB
/*global angular*/ (function () { 'use strict'; angular.module("angularplasmid", ["angularplasmid.services"]) .directive("plasmidapi", ['SVGUtil', function (SVGUtil) { return { restrict: "AE", link : function (scope, elem, attr) { scope[attr.name] = SVGUtil.api; } }; }]) .directive("plasmid", ['SVGUtil', function (SVGUtil) { return { restrict: 'AE', type : 'svg', template : '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"></svg>', replace : true, transclude: true, require: 'plasmid', scope: { plasmidheight : '@', plasmidwidth : '@', sequencelength : '@', sequence : '@', plasmidclass : '@', plasmidstyle : '@' }, link : { pre : function (scope, elem, attr, plasmidController) { plasmidController.init(elem); }, post : function (scope, elem, attrs, plasmidController, transcludeFn) { // Manually transclude children elements transcludeFn(scope.$parent, function (content) { elem.append(content); }); // Watch for changes to plasmid scope.$watchGroup(['plasmidheight', 'plasmidwidth', 'sequencelength', 'sequence', 'plasmidclass', 'plasmidstyle'], function () {plasmidController.draw(); }); } }, controller : ['$scope', 'SVGUtil', function ($scope, SVGUtil) { var element, plasmid, tracks = []; plasmid = this; plasmid.elementtype = "plasmid"; plasmid.init = function (elem) { SVGUtil.api.addPlasmid(plasmid); element = elem; plasmid.id = element.attr("id"); }; plasmid.draw = function () { var d = plasmid.dimensions, plasmidclass = element.plasmidclass, plasmidstyle = element.plasmidstyle; element.attr("height", d.height); element.attr("width", d.width); if (plasmidclass) {element.attr("class",plasmidclass);} if (plasmidstyle) {element.attr("style", plasmidstyle);} angular.forEach(tracks, function (t) { t.draw(); }); }; plasmid.addTrack = function (track) { tracks.push(track); }; Object.defineProperty(plasmid, "center", { get: function () { var d = plasmid.dimensions; return { x : d.width / 2, y : d.height / 2 }; } }); Object.defineProperty(plasmid, "dimensions", { get: function () { return { height : SVGUtil.util.Numeric($scope.plasmidheight, 300), width : SVGUtil.util.Numeric($scope.plasmidwidth, 300) }; } }); Object.defineProperty(plasmid, "sequencelength", { get: function () { return (plasmid.sequence ? plasmid.sequence.length : SVGUtil.util.Numeric($scope.sequencelength)); } }); Object.defineProperty(plasmid, "sequence", { get: function () { return $scope.sequence; } }); Object.defineProperty(plasmid, "plasmidclass", { get: function () { return $scope.plasmidclass; } }); Object.defineProperty(plasmid, "plasmidstyle", { get: function () { return $scope.plasmidstyle; } }); plasmid.tracks = tracks; }] }; }]) .directive("plasmidtrack", ['SVGUtil', '$compile', function (SVGUtil, $compile) { return { restrict: 'AE', type : 'svg', template: '<g><path></path></g>', replace : true, transclude: true, require: ['plasmidtrack', '^plasmid'], scope: { radius: '@', width: '@', trackclass: '@', trackstyle: '@', trackclick: '&' }, link : { pre : function (scope, elem, attr, controllers, transcludeFn) { var trackController = controllers[0], plasmidController = controllers[1], pathElem = angular.element(elem.children()[0]); trackController.init(pathElem, plasmidController); }, post : function (scope, elem, attr, controllers, transcludeFn) { // Manually transclude children elements transcludeFn(scope.$parent, function (content) { elem.append(content); }); // Apply special style to path to allow for correct display and apply directive's properties (class, style, id, name) to the path instead of the g var g = angular.element(elem), path = angular.element(elem.children()[0]), trackController = controllers[0]; SVGUtil.util.swapProperties(g, path); path.attr("fill-rule", "evenodd"); $compile(path)(scope.$parent); //Attach event handlers path.on("click", function (e) { scope.trackclick({ $event: e, $track: trackController }); }); // Watch for changes in the track scope.$watchGroup(['radius', 'width', 'trackstyle', 'trackclass'], function () {trackController.draw(); }); } }, controller : ['$scope', function ($scope) { var plasmid, element, plasmidTrack, markers = [], scales = [], labels = []; plasmidTrack = this; plasmidTrack.elementtype = "plasmidtrack"; plasmidTrack.init = function (elem, plasmidCtrl) { plasmid = plasmidCtrl; plasmid.addTrack(plasmidTrack); plasmidTrack.plasmid = plasmid; element = elem; }; plasmidTrack.draw = function () { var center = plasmidTrack.center, path = SVGUtil.svg.path.donut(center.x, center.y, plasmidTrack.radius, plasmidTrack.width), trackclass = plasmidTrack.trackclass, trackstyle = plasmidTrack.trackstyle; element.attr("d", path); if (trackclass) {element.attr("class",trackclass);} if (trackstyle) {element.attr("style", trackstyle);} angular.forEach(markers, function (m) { m.draw(); }); angular.forEach(scales, function (s) { s.draw(); }); angular.forEach(labels, function (l) { l.draw(); }); }; plasmidTrack.addMarker = function (marker) { markers.push(marker); }; plasmidTrack.addScale = function (scale) { scales.push(scale); }; plasmidTrack.addLabel = function (label) { labels.push(label); }; plasmidTrack.markergroup = function (groupName) { var items = []; angular.forEach(markers, function (marker) { if (marker.markergroup === groupName) { items.push(marker); } }); return items; }; plasmidTrack.getPosition = function (pos, positionOption, radiusAdjust) { radiusAdjust = Number(radiusAdjust || 0); pos = Number(pos); var POSITION_OPTION_MID = 0, POSITION_OPTION_INNER = 1, POSITION_OPTION_OUTER = 2, radius, angle, center = plasmidTrack.center, seqLen = plasmid.sequencelength; if (seqLen > 0) { angle = (pos / seqLen) * 360; switch (positionOption) { case POSITION_OPTION_INNER: radius = plasmidTrack.radius + radiusAdjust; break; case POSITION_OPTION_OUTER: radius = plasmidTrack.radius + plasmidTrack.width + radiusAdjust; break; default: radius = plasmidTrack.radius + (plasmidTrack.width / 2) + radiusAdjust; break; } return SVGUtil.util.polarToCartesian(center.x, center.y, radius, angle); } }; Object.defineProperty(plasmidTrack, "center", { get: function () { return plasmid.center; } }); Object.defineProperty(plasmidTrack, "radius", { get: function () { return SVGUtil.util.Numeric($scope.radius, 100); } }); Object.defineProperty(plasmidTrack, "width", { get: function () { return SVGUtil.util.Numeric($scope.width, 25); } }); Object.defineProperty(plasmidTrack, "trackclass", { get: function () { return $scope.trackclass; } }); Object.defineProperty(plasmidTrack, "trackstyle", { get: function () { return $scope.trackstyle; } }); plasmidTrack.markers = markers; plasmidTrack.scales = scales; plasmidTrack.labels = labels; }] }; }]) .directive("trackscale", ['SVGUtil', '$compile', function (SVGUtil, $compile) { return { restrict: 'AE', type : 'svg', template: '<g><path></path><g></g></g>', replace : true, transclude: true, require: ['trackscale', '^plasmidtrack'], scope: { interval: "@", vadjust: "@", ticksize: "@", direction: "@", showlabels : "@", labelvadjust : "@", labelclass : "@", labelstyle : "@", tickclass : "@", tickstyle : "@", scaleclick : "&" }, link : { pre : function (scope, elem, attr, controllers, transcludeFn) { var scaleController = controllers[0], trackController = controllers[1], pathElem = angular.element(elem.children()[0]), groupElem = angular.element(elem.children()[1]); scaleController.init(pathElem, groupElem, trackController); }, post : function (scope, elem, attr, controllers, transcludeFn) { var g, path, scaleController; //Manually transclude children elements transcludeFn(scope.$parent, function (content) { elem.append(content); }); //Apply directive's properties (class, style, id, name) to the path instead of the g g = angular.element(elem); path = angular.element(elem.children()[0]); SVGUtil.util.swapProperties(g, path); $compile(path)(scope.$parent); //Attach event handlers path.on("click", function (e) { scope.scaleclick({ $event: e, $scale: scaleController }); }); // Watch for changes to scale scaleController = controllers[0]; scope.$watchGroup(['interval', 'vadjust', 'ticksize', 'labelvadjust', 'direction', 'showlabels', 'labelstyle', 'labelclass','tickstyle','tickclass'], function () {scaleController.draw(); }); } }, controller : ['$scope', function ($scope) { var track, trackScale, element, groupElement, DEFAULT_LABELVADJUST = 15, DEFAULT_TICKSIZE = 3; trackScale = this; trackScale.elementtype = "trackscale"; trackScale.init = function (elem, groupElem, trackCtrl) { track = trackCtrl; track.addScale(trackScale); trackScale.track = track; element = elem; groupElement = groupElem; }; trackScale.draw = function () { var tickclass = trackScale.tickclass, tickstyle = trackScale.tickstyle, center = track.center, path = SVGUtil.svg.path.scale(center.x, center.y, trackScale.radius, trackScale.interval, trackScale.total, trackScale.ticksize); element.attr("d", path); if (tickclass) {element.attr("class",tickclass);} if (tickstyle) {element.attr("style", tickstyle);} if (trackScale.showlabels) { trackScale.drawLabel(); } else { groupElement.empty(); } }; trackScale.drawLabel = function () { var i, t, labels, center = track.center; function clickHandler(e) { $scope.scaleclick({ $event: e, $scale: trackScale }); } labels = SVGUtil.svg.element.scalelabels(center.x, center.y, trackScale.labelradius, trackScale.interval, trackScale.total); groupElement.empty(); for (i = 0; i <= labels.length - 1; i += 1) { t = angular.element(SVGUtil.svg.createNode('text')); if (trackScale.labelclass) { t.attr('class', trackScale.labelclass); } if (trackScale.labelstyle) { t.attr('style', trackScale.labelstyle); } t.attr("x", labels[i].x); t.attr("y", labels[i].y); t.attr("text-anchor", "middle"); t.attr("alignment-baseline", "middle"); t.text(labels[i].text); t.on("click", clickHandler); groupElement.append(t); } }; Object.defineProperty(trackScale, "radius", { get: function () { return (trackScale.inwardflg ? track.radius : track.radius + track.width) + ((trackScale.inwardflg ? -1 : 1) * trackScale.vadjust) + (trackScale.inwardflg ? -(trackScale.ticksize) : 0); } }); Object.defineProperty(trackScale, "interval", { get: function () { return SVGUtil.util.Numeric($scope.interval); } }); Object.defineProperty(trackScale, "vadjust", { get: function () { return SVGUtil.util.Numeric($scope.vadjust); } }); Object.defineProperty(trackScale, "ticksize", { get: function () { return SVGUtil.util.Numeric($scope.ticksize, DEFAULT_TICKSIZE); } }); Object.defineProperty(trackScale, "inwardflg", { get: function () { return $scope.direction === 'in' ? true : false; } }); Object.defineProperty(trackScale, "total", { get: function () { return track.plasmid.sequencelength; } }); Object.defineProperty(trackScale, "showlabels", { get: function () { return $scope.showlabels === "1" ? true : false; } }); Object.defineProperty(trackScale, "labelvadjust", { get: function () { return SVGUtil.util.Numeric($scope.labelvadjust, DEFAULT_LABELVADJUST); } }); Object.defineProperty(trackScale, "tickclass", { get: function () { return $scope.tickclass; } }); Object.defineProperty(trackScale, "tickstyle", { get: function () { return $scope.tickstyle; } }); Object.defineProperty(trackScale, "labelclass", { get: function () { return $scope.labelclass; } }); Object.defineProperty(trackScale, "labelstyle", { get: function () { return $scope.labelstyle; } }); Object.defineProperty(trackScale, "labelradius", { get: function () { return trackScale.radius + (trackScale.labelvadjust * (trackScale.inwardflg ? -1 : 1)); } }); }] }; }]) .directive("tracklabel", ['SVGUtil', function (SVGUtil) { return { restrict: 'AE', type : 'svg', template: '<text></text>', replace : true, transclude: true, require: ['tracklabel', '^plasmidtrack'], scope: { text: "@", hadjust : "@", vadjust : "@", labelclass: "@", labelstyle : '@', labelclick : "&" }, link : { pre : function (scope, elem, attr, controllers, transcludeFn) { var labelController = controllers[0], trackController = controllers[1], textElem = angular.element(elem[0]); labelController.init(textElem, trackController); }, post : function (scope, elem, attr, controllers, transcludeFn) { var labelController; //Manually transclude children elements transcludeFn(scope.$parent, function (content) { elem.append(content); }); // Set some default properties for the label display elem.attr("text-anchor", "middle"); elem.attr("alignment-baseline", "middle"); //Attach event handlers elem.on("click", function (e) { scope.labelclick({ $event: e, $label: labelController }); }); // Watch for changes to label labelController = controllers[0]; scope.$watchGroup(['text', 'vadjust', 'hadjust','labelstyle','labelclass'], function () {labelController.draw(); }); } }, controller : ['$scope', function ($scope) { var track, trackLabel, element; trackLabel = this; trackLabel.elementtype = "tracklabel"; trackLabel.init = function (elem, trackCtrl) { track = trackCtrl; track.addLabel(trackLabel); trackLabel.track = track; element = elem; }; trackLabel.draw = function () { var center = track.center, startX, startY, labelclass = trackLabel.labelclass, labelstyle = trackLabel.labelstyle; element.attr("x", center.x + trackLabel.hadjust); element.attr("y", center.y + trackLabel.vadjust); element.text(trackLabel.text); if (labelclass) {element.attr("class",labelclass);} if (labelstyle) {element.attr("style", labelstyle);} }; Object.defineProperty(trackLabel, "center", { get: function () { return track.center; } }); Object.defineProperty(trackLabel, "text", { get: function () { return $scope.text; } }); Object.defineProperty(trackLabel, "labelclass", { get: function () { return $scope.labelclass; } }); Object.defineProperty(trackLabel, "labelstyle", { get: function () { return $scope.labelstyle; } }); Object.defineProperty(trackLabel, "hadjust", { get: function () { return SVGUtil.util.Numeric($scope.hadjust, 0); } }); Object.defineProperty(trackLabel, "vadjust", { get: function () { return SVGUtil.util.Numeric($scope.vadjust, 0); } }); Object.defineProperty(trackLabel, "dimensions", { get: function () { return element[0].getBBox(); } }); }] }; }]) .directive("trackmarker", ['SVGUtil', '$compile', function (SVGUtil, $compile) { return { restrict: 'AE', type : 'svg', template: '<g><path></path></g>', replace : true, transclude: true, require: ['trackmarker', '^plasmidtrack'], scope: { start: "@", end: "@", vadjust: "@", wadjust: "@", markergroup: "@", arrowstartlength : "@", arrowstartwidth : "@", arrowstartangle : "@", arrowendlength : "@", arrowendwidth : "@", arrowendangle : "@", markerclass : "@", markerstyle : "@", markerclick: "&" }, link : { pre : function (scope, elem, attr, controllers, transcludeFn) { var markerController = controllers[0], trackController = controllers[1], pathElem = angular.element(elem.children()[0]); markerController.init(pathElem, trackController); }, post : function (scope, elem, attr, controllers, transcludeFn) { var markerController = controllers[0], g, path; //Manually transclude children elements transcludeFn(scope.$parent, function (content) { elem.append(content); }); //Apply directive's properties (class, style, id, name) to the path instead of the g g = angular.element(elem); path = angular.element(elem.children()[0]); SVGUtil.util.swapProperties(g, path); $compile(path)(scope.$parent); //Attach event handlers path.on("click", function (e) { scope.markerclick({ $event: e, $marker: markerController }); }); // Watch for changes to marker scope.$watchGroup(['start', 'end', 'vadjust', 'wadjust', 'markergroup', 'markerclass','markerstyle','arrowstartlength', 'arrowstartwidth', 'arrowstartangle', 'arrowendlength', 'arrowendwidth', 'arrowendangle'], function () {markerController.draw(); }); } }, controller : ['$scope', function ($scope) { var track, marker, element, markerLabels = []; marker = this; marker.elementtype = "trackmarker"; marker.init = function (elem, trackCtrl) { track = trackCtrl; track.addMarker(marker); element = elem; marker.track = track; }; marker.draw = function () { var markerclass = marker.markerclass, markerstyle = marker.markerstyle; element.attr("d", marker.getPath()); if (markerclass) {element.attr("class",markerclass);} if (markerstyle) {element.attr("style", markerstyle);} angular.forEach(markerLabels, function (markerLabel) { markerLabel.draw(); }); }; marker.addMarkerLabel = function (markerLabel) { markerLabels.push(markerLabel); }; marker.getPath = function () { var center = track.center, angle = marker.angle, radius = marker.radius; return SVGUtil.svg.path.arc(center.x, center.y, radius.inner, angle.start, angle.end, marker.width, marker.arrowstart, marker.arrowend); }; marker.getPosition = function (hAdjust, vAdjust, hAlign, vAlign) { var HALIGN_MIDDLE = "middle", HALIGN_START = "start", HALIGN_END = "end", VALIGN_MIDDLE = "middle", VALIGN_INNER = "inner", VALIGN_OUTER = "outer", center, radius, angle, markerRadius, markerAngle; center = track.center; markerRadius = marker.radius; markerAngle = marker.angle; hAdjust = SVGUtil.util.Numeric(hAdjust); vAdjust = SVGUtil.util.Numeric(vAdjust); if (vAlign !== undefined && hAlign !== undefined) { switch (vAlign) { case VALIGN_INNER: radius = markerRadius.inner + vAdjust; break; case VALIGN_OUTER: radius = markerRadius.outer + vAdjust; break; default: radius = markerRadius.middle + vAdjust; break; } switch (hAlign) { case HALIGN_START: angle = markerAngle.start + hAdjust; break; case HALIGN_END: angle = markerAngle.end + hAdjust; break; default: angle = markerAngle.middle + hAdjust; break; } return SVGUtil.util.polarToCartesian(center.x, center.y, radius, angle); } else { radius = { outer : markerRadius.outer + vAdjust, inner : markerRadius.inner + vAdjust, middle : markerRadius.middle + vAdjust }; angle = { begin : markerAngle.start + hAdjust, end : markerAngle.end + hAdjust, middle : markerAngle.middle + hAdjust }; return { outer : { begin: SVGUtil.util.polarToCartesian(center.x, center.y, radius.outer, angle.begin), middle: SVGUtil.util.polarToCartesian(center.x, center.y, radius.outer, angle.middle), end: SVGUtil.util.polarToCartesian(center.x, center.y, radius.outer, angle.end) }, middle : { begin: SVGUtil.util.polarToCartesian(center.x, center.y, radius.middle, angle.begin), middle: SVGUtil.util.polarToCartesian(center.x, center.y, radius.middle, angle.middle), end: SVGUtil.util.polarToCartesian(center.x, center.y, radius.middle, angle.end) }, inner : { begin: SVGUtil.util.polarToCartesian(center.x, center.y, radius.inner, angle.begin), middle: SVGUtil.util.polarToCartesian(center.x, center.y, radius.inner, angle.middle), end: SVGUtil.util.polarToCartesian(center.x, center.y, radius.inner, angle.end) } }; } }; marker.fireClick = function (event) { $scope.markerclick({ $event: event.$event, $marker: event.$marker }); }; Object.defineProperty(marker, "center", { get: function () { return track.center; } }); Object.defineProperty(marker, "radius", { get: function () { return { inner : track.radius + marker.vadjust, outer : track.radius + marker.vadjust + marker.width, middle : track.radius + marker.vadjust + marker.width / 2 }; } }); Object.defineProperty(marker, "angle", { get: function () { var startAngle, endAngle, midAngle, end; startAngle = (marker.start / track.plasmid.sequencelength) * 360; end = $scope.end || $scope.start; endAngle = (SVGUtil.util.Numeric(end) / track.plasmid.sequencelength) * 360; endAngle += (endAngle < startAngle) ? 360 : 0; midAngle = startAngle + ((endAngle - startAngle) / 2); return { start : startAngle, middle : midAngle, end : endAngle }; } }); Object.defineProperty(marker, "vadjust", { get: function () { return SVGUtil.util.Numeric($scope.vadjust); } }); Object.defineProperty(marker, "wadjust", { get: function () { return SVGUtil.util.Numeric($scope.wadjust); } }); Object.defineProperty(marker, "width", { get: function () { return track.width + marker.wadjust; } }); Object.defineProperty(marker, "start", { get: function () { return SVGUtil.util.Numeric($scope.start); } }); Object.defineProperty(marker, "end", { get: function () { return SVGUtil.util.Numeric($scope.end); } }); Object.defineProperty(marker, "arrowstart", { get: function () { return { width : SVGUtil.util.Numeric($scope.arrowstartwidth), length : SVGUtil.util.Numeric($scope.arrowstartlength), angle : SVGUtil.util.Numeric($scope.arrowstartangle) }; } }); Object.defineProperty(marker, "arrowend", { get: function () { return { width : SVGUtil.util.Numeric($scope.arrowendwidth), length : SVGUtil.util.Numeric($scope.arrowendlength), angle : SVGUtil.util.Numeric($scope.arrowendangle) }; } }); Object.defineProperty(marker, "markergroup", { get: function () { return $scope.markergroup; } }); Object.defineProperty(marker, "markerclass", { get: function () { return $scope.markerclass; } }); Object.defineProperty(marker, "markerstyle", { get: function () { return $scope.markerstyle; } }); Object.defineProperty(marker, "sequence", { get: function () { var plasmidSeq = marker.track.plasmid.sequence, markerSeq = ''; if (marker.start > marker.end) { return plasmidSeq.substring(marker.start - 1, plasmidSeq.length - 1) + plasmidSeq.substring(0, marker.end - 1); } else { return plasmidSeq.substring(marker.start - 1, marker.end - 1); } } }); marker.labels = markerLabels; }] }; }]) .directive("markerlabel", ['SVGUtil', '$compile', function (SVGUtil, $compile) { return { restrict: 'AE', type : 'svg', transclude: true, template: '<g><path></path><path id="" style="fill:none;stroke:none"></path><text></text></g>', require: ['markerlabel', '^trackmarker'], replace : true, scope: { text : "@", valign : "@", vadjust : "@", halign : "@", hadjust : "@", type : "@", showline : "@", linestyle : "@", lineclass : "@", labelstyle : "@", labelclass : "@", linevadjust : "@", labelclick : "&" }, link: { pre : function (scope, elem, attr, controllers, transcludeFn) { var markerlabelController = controllers[0], trackMarkerController = controllers[1], groupElem = angular.element(elem[0]), lineElem = angular.element(elem.children()[0]), pathElem = angular.element(elem.children()[1]), textElem = angular.element(elem.children()[2]); markerlabelController.init(textElem, groupElem, pathElem, lineElem, trackMarkerController); }, post : function (scope, elem, attr, controllers, transcludeFn) { transcludeFn(scope.$parent, function (content) { elem.append(content); }); var markerlabelController = controllers[0], trackMarkerController = controllers[1], g = angular.element(elem), text = angular.element(elem.children()[2]); //Apply directive's properties (class, style, id, name) to the text text.attr("text-anchor", "middle"); text.attr("alignment-baseline", "middle"); SVGUtil.util.swapProperties(g, text); $compile(text)(scope.$parent); //Attach event handlers if (attr.labelclick) { text.on("click", function (e) { scope.labelclick({ $event: e, $label: markerlabelController }); }); // or bubble up events to the marker } else { text.on("click", function (e) { trackMarkerController.fireClick({ $event: e, $marker: trackMarkerController }); }); } // Watch for changes to label scope.$watchGroup(['text', 'type', 'valign', 'vadjust', 'halign', 'hadjust', 'showline', 'linevadjust', 'linestyle', 'labelclass','labelstyle'], function () {markerlabelController.draw(); }); } }, controller : ['$scope', '$compile', function ($scope, $compile) { var marker, markerLabel, textElement, pathElement, textPathElement, textPathSVG, lineElement, groupElement; markerLabel = this; markerLabel.elementtype = "markerlabel"; markerLabel.init = function (textElem, groupElem, pathElem, lineElem, markerCtrl) { var id = 'TPATH' + (Math.random() + 1).toString(36).substring(3, 7); marker = markerCtrl; marker.addMarkerLabel(markerLabel); markerLabel.marker = marker; textElement = textElem; pathElement = pathElem; lineElement = lineElem; groupElement = groupElem; pathElement.attr("id", id); }; markerLabel.draw = function () { var VALIGN_MIDDLE = "middle", VALIGN_INNER = "inner", VALIGN_OUTER = "outer", HALIGN_MIDDLE = "middle", HALIGN_START = "start", HALIGN_END = "end", fontSize = 0, fontAdjust = 0, labelclass = markerLabel.labelclass, labelstyle = markerLabel.labelstyle, pos, markerAngle, src, dst, dstPos, dstV; if (labelclass) {textElement.attr("class",labelclass);} if (labelstyle) {textElement.attr("style", labelstyle);} if (markerLabel.type === 'path') { textElement.attr("x",''); textElement.attr("y",''); if (!textPathElement){ textPathSVG = document.createElementNS('http://www.w3.org/2000/svg','textPath'); textPathSVG.setAttributeNS("http://www.w3.org/1999/xlink", "href", "#" + pathElement.attr("id")); textPathElement = angular.element(textPathSVG); $compile(textPathElement)($scope); textElement.empty(); textElement.append(textPathElement); } textPathSVG.textContent = markerLabel.text; fontSize = window.getComputedStyle(textElement[0]).fontSize.replace("px", ""); fontAdjust = (markerLabel.valign === VALIGN_OUTER) ? 0 : (markerLabel.valign === VALIGN_INNER) ? Number(fontSize || 0) : Number(fontSize || 0) / 2; pathElement.attr("d", markerLabel.getPath(markerLabel.hadjust, markerLabel.vadjust - fontAdjust, markerLabel.halign, markerLabel.valign)); switch (markerLabel.halign) { case HALIGN_START: textElement.attr("text-anchor", "start"); textPathElement[0].setAttribute("startOffset", "0%"); //jQuery can't handle case sensitive names so can't use textPathElem.attr break; case HALIGN_END: textElement.attr("text-anchor", "end"); textPathElement[0].setAttribute("startOffset", "100%");//jQuery can't handle case sensitive names so can't use textPathElem.attr break; default: textElement.attr("text-anchor", "middle"); textPathElement[0].setAttribute("startOffset", "50%");//jQuery can't handle case sensitive names so can't use textPathElem.attr break; } } else { if (textPathElement){ textPathElement.remove(); textPathElement = null; } pos = marker.getPosition(markerLabel.hadjust, markerLabel.vadjust, markerLabel.halign, markerLabel.valign); textElement.attr("x", pos.x); textElement.attr("y", pos.y); textElement.text(markerLabel.text); } if (markerLabel.showlineflg) { src = marker.getPosition(markerLabel.hadjust, markerLabel.vadjust + markerLabel.linevadjust, markerLabel.halign, markerLabel.valign); dstPos = marker.getPosition(); dstV = markerLabel.valign === VALIGN_INNER ? dstPos.inner : markerLabel.valign === VALIGN_MIDDLE ? dstPos.middle : dstPos.outer; dst = markerLabel.halign === HALIGN_START ? dstV.begin : markerLabel.halign === HALIGN_END ? dstV.end : dstV.middle; lineElement.attr("d", ["M", src.x, src.y, "L", dst.x, dst.y].join(" ")); if (!markerLabel.linestyle && !markerLabel.lineclass) { lineElement.attr("style", "stroke:#000"); } if (markerLabel.linestyle) { lineElement.attr("style", markerLabel.linestyle); } if (markerLabel.lineclass) { lineElement.attr("class", markerLabel.lineclass); } } else { lineElement.removeAttr("d"); } }; markerLabel.getPath = function (hAdjust, vAdjust, hAlign, vAlign) { var VALIGN_MIDDLE = "middle", VALIGN_INNER = "inner", VALIGN_OUTER = "outer", HALIGN_MIDDLE = "middle", HALIGN_START = "start", HALIGN_END = "end", center = marker.center, radius, markerRadius, markerAngle, startAngle, endAngle; markerRadius = marker.radius; switch (vAlign) { case VALIGN_INNER: radius = markerRadius.inner; break; case VALIGN_OUTER: radius = markerRadius.outer; break; default: radius = markerRadius.middle; break; } markerAngle = marker.angle; switch (hAlign) { case HALIGN_START: startAngle = markerAngle.start; endAngle = markerAngle.start + 359.99; break; case HALIGN_END: startAngle = markerAngle.end