UNPKG

d3-svg-annotation

Version:

Full documentation: [http://d3-annotation.susielu.com](http://d3-annotation.susielu.com)

1,604 lines (1,357 loc) 60.4 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-selection'), require('d3-drag'), require('d3-shape'), require('d3-dispatch')) : typeof define === 'function' && define.amd ? define(['exports', 'd3-selection', 'd3-drag', 'd3-shape', 'd3-dispatch'], factory) : (factory((global.indexRollup = global.indexRollup || {}),global.d3Selection,global.d3Drag,global.d3Shape,global.d3Dispatch)); }(this, function (exports,d3Selection,d3Drag,d3Shape,d3Dispatch) { 'use strict'; var asyncGenerator = function () { function AwaitValue(value) { this.value = value; } function AsyncGenerator(gen) { var front, back; function send(key, arg) { return new Promise(function (resolve, reject) { var request = { key: key, arg: arg, resolve: resolve, reject: reject, next: null }; if (back) { back = back.next = request; } else { front = back = request; resume(key, arg); } }); } function resume(key, arg) { try { var result = gen[key](arg); var value = result.value; if (value instanceof AwaitValue) { Promise.resolve(value.value).then(function (arg) { resume("next", arg); }, function (arg) { resume("throw", arg); }); } else { settle(result.done ? "return" : "normal", result.value); } } catch (err) { settle("throw", err); } } function settle(type, value) { switch (type) { case "return": front.resolve({ value: value, done: true }); break; case "throw": front.reject(value); break; default: front.resolve({ value: value, done: false }); break; } front = front.next; if (front) { resume(front.key, front.arg); } else { back = null; } } this._invoke = send; if (typeof gen.return !== "function") { this.return = undefined; } } if (typeof Symbol === "function" && Symbol.asyncIterator) { AsyncGenerator.prototype[Symbol.asyncIterator] = function () { return this; }; } AsyncGenerator.prototype.next = function (arg) { return this._invoke("next", arg); }; AsyncGenerator.prototype.throw = function (arg) { return this._invoke("throw", arg); }; AsyncGenerator.prototype.return = function (arg) { return this._invoke("return", arg); }; return { wrap: function (fn) { return function () { return new AsyncGenerator(fn.apply(this, arguments)); }; }, await: function (value) { return new AwaitValue(value); } }; }(); var classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; var createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; var inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }; var possibleConstructorReturn = function (self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }; var toConsumableArray = function (arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } }; var Annotation = function () { function Annotation(_ref) { var _ref$x = _ref.x, x = _ref$x === undefined ? 0 : _ref$x, _ref$y = _ref.y, y = _ref$y === undefined ? 0 : _ref$y, _ref$dy = _ref.dy, dy = _ref$dy === undefined ? 0 : _ref$dy, _ref$dx = _ref.dx, dx = _ref$dx === undefined ? 0 : _ref$dx, data = _ref.data, type = _ref.type, subject = _ref.subject, connector = _ref.connector, note = _ref.note, disable = _ref.disable, id = _ref.id, className = _ref.className; classCallCheck(this, Annotation); this._dx = dx; this._dy = dy; this._x = x; this._y = y; this.id = id; this._className = className || ''; this.type = type || ''; this.data = data; this.note = note || {}; this.connector = connector || {}; this.subject = subject || {}; this.disable = disable || []; } createClass(Annotation, [{ key: 'updatePosition', value: function updatePosition() { if (this.type.setPosition) { this.type.setPosition(); if (this.type.subject.selectAll(':not(.handle)').nodes().length !== 0) { this.type.redrawSubject(); } } } }, { key: 'updateOffset', value: function updateOffset() { if (this.type.setOffset) { this.type.setOffset(); if (this.type.connector.selectAll(':not(.handle)').nodes().length !== 0) { this.type.redrawConnector(); } this.type.redrawNote(); } } }, { key: 'className', get: function get() { return this._className; }, set: function set(className) { this._className = className; if (this.type.setClassName) this.type.setClassName(); } }, { key: 'x', get: function get() { return this._x; }, set: function set(x) { this._x = x; this.updatePosition(); } }, { key: 'y', get: function get() { return this._y; }, set: function set(y) { this._y = y; this.updatePosition(); } }, { key: 'dx', get: function get() { return this._dx; }, set: function set(dx) { this._dx = dx; this.updateOffset(); } }, { key: 'dy', get: function get() { return this._dy; }, set: function set(dy) { this._dy = dy; this.updateOffset(); } }, { key: 'offset', get: function get() { return { x: this._dx, y: this._dy }; }, set: function set(_ref2) { var x = _ref2.x, y = _ref2.y; this._dx = x; this._dy = y; this.updateOffset(); } }, { key: 'position', get: function get() { return { x: this._x, y: this._y }; }, set: function set(_ref3) { var x = _ref3.x, y = _ref3.y; this._x = x; this._y = y; this.updatePosition(); } }, { key: 'translation', get: function get() { return { x: this._x + this._dx, y: this._y + this._dy }; } }, { key: 'json', get: function get() { var json = { x: this._x, y: this._y, dx: this._dx, dy: this._dy }; if (this.data && Object.keys(this.data).length > 0) json.data = this.data; if (this.type) json.type = this.type; if (this._className) json.className = this._className; if (Object.keys(this.connector).length > 0) json.connector = this.connector; if (Object.keys(this.subject).length > 0) json.subject = this.subject; if (Object.keys(this.note).length > 0) json.note = this.note; return json; } }]); return Annotation; }(); var AnnotationCollection = function () { function AnnotationCollection(_ref) { var annotations = _ref.annotations, accessors = _ref.accessors, accessorsInverse = _ref.accessorsInverse; classCallCheck(this, AnnotationCollection); this.accessors = accessors; this.accessorsInverse = accessorsInverse; this.annotations = annotations; } createClass(AnnotationCollection, [{ key: "clearTypes", value: function clearTypes(newSettings) { this.annotations.forEach(function (d) { d.type = undefined; d.subject = newSettings && newSettings.subject || d.subject; d.connector = newSettings && newSettings.connector || d.connector; d.note = newSettings && newSettings.note || d.note; }); } }, { key: "setPositionWithAccessors", value: function setPositionWithAccessors() { var _this = this; this.annotations.forEach(function (d) { d.type.setPositionWithAccessors(_this.accessors); }); } }, { key: "editMode", value: function editMode(_editMode) { this.annotations.forEach(function (a) { if (a.type) { a.type.editMode = _editMode; a.type.updateEditMode(); } }); } }, { key: "updateDisable", value: function updateDisable(disable) { this.annotations.forEach(function (a) { a.disable = disable; if (a.type) { disable.forEach(function (d) { if (a.type[d]) { a.type[d].remove && a.type[d].remove(); a.type[d] = undefined; } }); } }); } }, { key: "updateTextWrap", value: function updateTextWrap(textWrap) { this.annotations.forEach(function (a) { if (a.type && a.type.updateTextWrap) { a.type.updateTextWrap(textWrap); } }); } }, { key: "updateNotePadding", value: function updateNotePadding(notePadding) { this.annotations.forEach(function (a) { if (a.type) { a.type.notePadding = notePadding; } }); } }, { key: "json", get: function get() { var _this2 = this; return this.annotations.map(function (a) { var json = a.json; if (_this2.accessorsInverse && a.data) { json.data = {}; Object.keys(_this2.accessorsInverse).forEach(function (k) { json.data[k] = _this2.accessorsInverse[k]({ x: a.x, y: a.y }); //TODO make this feasible to map back to data for other types of subjects }); } return json; }); } }, { key: "noteNodes", get: function get() { return this.annotations.map(function (a) { return _extends({}, a.type.getNoteBBoxOffset(), { positionX: a.x, positionY: a.y }); }); } //TODO: come back and rethink if a.x and a.y are applicable in all situations // get connectorNodes() { // return this.annotations.map(a => ({ ...a.type.getConnectorBBox(), startX: a.x, startY: a.y})) // } // get subjectNodes() { // return this.annotations.map(a => ({ ...a.type.getSubjectBBox(), startX: a.x, startY: a.y})) // } // get annotationNodes() { // return this.annotations.map(a => ({ ...a.type.getAnnotationBBox(), startX: a.x, startY: a.y})) // } }]); return AnnotationCollection; }(); var pointHandle = function pointHandle(_ref) { var _ref$cx = _ref.cx, cx = _ref$cx === undefined ? 0 : _ref$cx, _ref$cy = _ref.cy, cy = _ref$cy === undefined ? 0 : _ref$cy; return { move: { x: cx, y: cy } }; }; var circleHandles = function circleHandles(_ref2) { var _ref2$cx = _ref2.cx, cx = _ref2$cx === undefined ? 0 : _ref2$cx, _ref2$cy = _ref2.cy, cy = _ref2$cy === undefined ? 0 : _ref2$cy, r1 = _ref2.r1, r2 = _ref2.r2, padding = _ref2.padding; var h = { move: { x: cx, y: cy } }; if (r1 !== undefined) { h.r1 = { x: cx + r1 / Math.sqrt(2), y: cy + r1 / Math.sqrt(2) }; } if (r2 !== undefined) { h.r2 = { x: cx + r2 / Math.sqrt(2), y: cy + r2 / Math.sqrt(2) }; } if (padding !== undefined) { h.padding = { x: cx + r1 + padding, y: cy }; } return h; }; //arc handles var addHandles = function addHandles(_ref5) { var group = _ref5.group, handles = _ref5.handles, _ref5$r = _ref5.r, r = _ref5$r === undefined ? 10 : _ref5$r; //give it a group and x,y to draw handles //then give it instructions on what the handles change var h = group.selectAll('circle.handle').data(handles); h.enter().append('circle').attr('class', 'handle').call(d3Drag.drag().container(d3Selection.select('g.annotations').node()).on('start', function (d) { return d.start && d.start(d); }).on('drag', function (d) { return d.drag && d.drag(d); }).on('end', function (d) { return d.end && d.end(d); })); group.selectAll('circle.handle').attr('cx', function (d) { return d.x; }).attr('cy', function (d) { return d.y; }).attr('r', function (d) { return d.r || r; }).attr('class', function (d) { return 'handle ' + (d.className || ''); }); h.exit().remove(); }; var leftRightDynamic = function leftRightDynamic(align, y) { if (align == "dynamic" || align == "left" || align == "right") { if (y < 0) { align = "top"; } else { align = "bottom"; } } return align; }; var topBottomDynamic = function topBottomDynamic(align, x) { if (align == "dynamic" || align == "top" || align == "bottom") { if (x < 0) { align = "right"; } else { align = "left"; } } return align; }; var noteAlignment = (function (_ref) { var padding = _ref.padding, bbox = _ref.bbox, align = _ref.align, orientation = _ref.orientation, offset = _ref.offset; var x = -bbox.x; var y = -bbox.y; if (orientation === "topBottom") { align = topBottomDynamic(align, offset.x); if (offset.y < 0) { y -= bbox.height + padding; } else { y += padding; } if (align === "middle") { x -= bbox.width / 2; } else if (align === "right") { x -= bbox.width; } } else if (orientation === "leftRight") { align = leftRightDynamic(align, offset.y); if (offset.x < 0) { x -= bbox.width + padding; } else { x += padding; } if (align === "middle") { y -= bbox.height / 2; } else if (align === "top") { y -= bbox.height; } } return { x: x, y: y }; }); var lineBuilder = function lineBuilder(_ref) { var data = _ref.data, _ref$curve = _ref.curve, curve = _ref$curve === undefined ? d3Shape.curveLinear : _ref$curve, canvasContext = _ref.canvasContext, className = _ref.className; var lineGen = d3Shape.line().curve(curve); var builder = { type: 'path', className: className, data: data }; if (canvasContext) { lineGen.context(canvasContext); builder.pathMethods = lineGen; } else { builder.attrs = { d: lineGen(data) }; } return builder; }; var arcBuilder = function arcBuilder(_ref2) { var data = _ref2.data, canvasContext = _ref2.canvasContext, className = _ref2.className; var builder = { type: 'path', className: className, data: data }; var arcShape = d3Shape.arc().innerRadius(data.innerRadius || 0).outerRadius(data.outerRadius || data.radius || 2).startAngle(data.startAngle || 0).endAngle(data.endAngle || 2 * Math.PI); if (canvasContext) { arcShape.context(canvasContext); builder.pathMethods = lineGen; } else { builder.attrs = { d: arcShape() }; } return builder; }; var noteVertical = (function (_ref) { var align = _ref.align, _ref$x = _ref.x, x = _ref$x === undefined ? 0 : _ref$x, _ref$y = _ref.y, y = _ref$y === undefined ? 0 : _ref$y, bbox = _ref.bbox, offset = _ref.offset, padding = _ref.padding; align = leftRightDynamic(align, offset.y); if (align == "top") { y -= bbox.height; } else if (align == "middle") { y -= bbox.height / 2; } var data = [[x, y], [x, y + bbox.height]]; return { components: [lineBuilder({ data: data, className: "note-line" })] }; }); var noteHorizontal = (function (_ref) { var align = _ref.align, _ref$x = _ref.x, x = _ref$x === undefined ? 0 : _ref$x, _ref$y = _ref.y, y = _ref$y === undefined ? 0 : _ref$y, offset = _ref.offset, bbox = _ref.bbox, padding = _ref.padding; align = topBottomDynamic(align, offset.x); if (align == "right") { x -= bbox.width; } else if (align == "middle") { x -= bbox.width / 2; } var data = [[x, y], [x + bbox.width, y]]; return { components: [lineBuilder({ data: data, className: "note-line" })] }; }); var lineSetup = function lineSetup(_ref) { var type = _ref.type, subjectType = _ref.subjectType; var annotation = type.annotation; var offset = annotation.position; var x1 = annotation.x - offset.x, x2 = x1 + annotation.dx, y1 = annotation.y - offset.y, y2 = y1 + annotation.dy; var subjectData = annotation.subject; if (subjectType == "circle" && (subjectData.outerRadius || subjectData.radius)) { var h = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); var angle = Math.asin(-y2 / h); var r = subjectData.outerRadius || subjectData.radius + (subjectData.radiusPadding || 0); x1 = Math.abs(Math.cos(angle) * r) * (x2 < 0 ? -1 : 1); y1 = Math.abs(Math.sin(angle) * r) * (y2 < 0 ? -1 : 1); } if (subjectType == "rect") { var width = subjectData.width, height = subjectData.height; if (width > 0 && annotation.dx > 0 || width < 0 && annotation.dx < 0) { if (Math.abs(width) > Math.abs(annotation.dx)) x1 = width / 2;else x1 = width; } if (height > 0 && annotation.dy > 0 || height < 0 && annotation.dy < 0) { if (Math.abs(height) > Math.abs(annotation.dy)) y1 = height / 2;else y1 = height; } if (x1 == width / 2 && y1 == height / 2) { x1 = x2;y1 = y2; } } return [[x1, y1], [x2, y2]]; }; var connectorLine = (function (connectorData) { var data = lineSetup(connectorData); return { components: [lineBuilder({ data: data, className: "connector" })] }; }); var connectorElbow = (function (_ref) { var type = _ref.type, subjectType = _ref.subjectType; var annotation = type.annotation; var offset = annotation.position; var x1 = annotation.x - offset.x, x2 = x1 + annotation.dx, y1 = annotation.y - offset.y, y2 = y1 + annotation.dy; var subjectData = annotation.subject; if (subjectType == "rect") { var width = subjectData.width, height = subjectData.height; if (width > 0 && annotation.dx > 0 || width < 0 && annotation.dx < 0) { if (Math.abs(width) > Math.abs(annotation.dx)) x1 = width / 2;else x1 = width; } if (height > 0 && annotation.dy > 0 || height < 0 && annotation.dy < 0) { if (Math.abs(height) > Math.abs(annotation.dy)) y1 = height / 2;else y1 = height; } if (x1 == width / 2 && y1 == height / 2) { x1 = x2;y1 = y2; } } var data = [[x1, y1], [x2, y2]]; var diffY = y2 - y1; var diffX = x2 - x1; var xe = x2; var ye = y2; var opposite = y2 < y1 && x2 > x1 || x2 < x1 && y2 > y1 ? -1 : 1; if (Math.abs(diffX) < Math.abs(diffY)) { xe = x2; ye = y1 + diffX * opposite; } else { ye = y2; xe = x1 + diffY * opposite; } if (subjectType == "circle" && (subjectData.outerRadius || subjectData.radius)) { var r = (subjectData.outerRadius || subjectData.radius) + (subjectData.radiusPadding || 0); var length = r / Math.sqrt(2); if (Math.abs(diffX) > length && Math.abs(diffY) > length) { x1 = length * (x2 < 0 ? -1 : 1); y1 = length * (y2 < 0 ? -1 : 1); data = [[x1, y1], [xe, ye], [x2, y2]]; } else if (Math.abs(diffX) > Math.abs(diffY)) { var angle = Math.asin(-y2 / r); x1 = Math.abs(Math.cos(angle) * r) * (x2 < 0 ? -1 : 1); data = [[x1, y2], [x2, y2]]; } else { var _angle = Math.acos(x2 / r); y1 = Math.abs(Math.sin(_angle) * r) * (y2 < 0 ? -1 : 1); data = [[x2, y1], [x2, y2]]; } } else { data = [[x1, y1], [xe, ye], [x2, y2]]; } return { components: [lineBuilder({ data: data, className: "connector" })] }; }); var connectorCurve = (function (_ref) { var type = _ref.type, connectorData = _ref.connectorData, subjectType = _ref.subjectType; if (!connectorData) { connectorData = {}; } if (!connectorData.points || typeof connectorData.points === "number") { connectorData.points = createPoints(type.annotation.offset, connectorData.points); } if (!connectorData.curve) { connectorData.curve = d3Shape.curveCatmullRom; } var handles = []; if (type.editMode) { (function () { var cHandles = connectorData.points.map(function (c, i) { return _extends({}, pointHandle({ cx: c[0], cy: c[1] }), { index: i }); }); var updatePoint = function updatePoint(index) { connectorData.points[index][0] += d3Selection.event.dx; connectorData.points[index][1] += d3Selection.event.dy; type.redrawConnector(); }; handles = type.mapHandles(cHandles.map(function (h) { return _extends({}, h.move, { drag: updatePoint.bind(type, h.index) }); })); })(); } var data = lineSetup({ type: type, subjectType: subjectType }); data = [data[0]].concat(toConsumableArray(connectorData.points), [data[1]]); var components = [lineBuilder({ data: data, curve: connectorData.curve, className: "connector" })]; return { components: components, handles: handles }; }); var createPoints = function createPoints(offset) { var anchors = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 2; var diff = { x: offset.x / (anchors + 1), y: offset.y / (anchors + 1) }; var p = []; var i = 1; for (; i <= anchors; i++) { p.push([diff.x * i + i % 2 * 20, diff.y * i - i % 2 * 20]); } return p; }; var connectorArrow = (function (_ref) { var annotation = _ref.annotation, start = _ref.start, end = _ref.end; var offset = annotation.position; if (!start) { start = [annotation.dx, annotation.dy]; } else { start = [-end[0] + start[0], -end[1] + start[1]]; } if (!end) { end = [annotation.x - offset.x, annotation.y - offset.y]; } var x1 = end[0], y1 = end[1]; var dx = start[0]; var dy = start[1]; var size = 10; var angleOffset = 16 / 180 * Math.PI; var angle = Math.atan(dy / dx); if (dx < 0) { angle += Math.PI; } var data = [[x1, y1], [Math.cos(angle + angleOffset) * size + x1, Math.sin(angle + angleOffset) * size + y1], [Math.cos(angle - angleOffset) * size + x1, Math.sin(angle - angleOffset) * size + y1], [x1, y1]]; //TODO add in reverse // if (canvasContext.arrowReverse){ // data = [[x1, y1], // [Math.cos(angle + angleOffset)*size, Math.sin(angle + angleOffset)*size], // [Math.cos(angle - angleOffset)*size, Math.sin(angle - angleOffset)*size], // [x1, y1] // ] // } else { // data = [[x1, y1], // [Math.cos(angle + angleOffset)*size, Math.sin(angle + angleOffset)*size], // [Math.cos(angle - angleOffset)*size, Math.sin(angle - angleOffset)*size], // [x1, y1] // ] // } return { components: [lineBuilder({ data: data, className: 'connector-arrow' })] }; }); var connectorDot = (function (_ref) { var line = _ref.line; var dot = arcBuilder({ className: 'connector-dot', data: { radius: 3 } }); dot.attrs.transform = 'translate(' + line.data[0][0] + ', ' + line.data[0][1] + ')'; return { components: [dot] }; }); var subjectCircle = (function (_ref) { var subjectData = _ref.subjectData, type = _ref.type; if (!subjectData.radius && !subjectData.outerRadius) { subjectData.radius = 20; } var handles = []; var c = arcBuilder({ data: subjectData, className: "subject" }); if (type.editMode) { var h = circleHandles({ r1: c.data.outerRadius || c.data.radius, r2: c.data.innerRadius, padding: subjectData.radiusPadding }); var updateRadius = function updateRadius(attr) { var r = subjectData[attr] + d3Selection.event.dx * Math.sqrt(2); subjectData[attr] = r; type.redrawSubject(); type.redrawConnector(); }; var cHandles = [_extends({}, h.r1, { drag: updateRadius.bind(type, subjectData.outerRadius !== undefined ? 'outerRadius' : 'radius') })]; if (subjectData.innerRadius) { cHandles.push(_extends({}, h.r2, { drag: updateRadius.bind(type, 'innerRadius') })); } handles = type.mapHandles(cHandles); } return { components: [c], handles: handles }; }); var subjectRect = (function (_ref) { var subjectData = _ref.subjectData, type = _ref.type; if (!subjectData.width) { subjectData.width = 100; } if (!subjectData.height) { subjectData.height = 100; } var handles = []; var width = subjectData.width, height = subjectData.height; var data = [[0, 0], [width, 0], [width, height], [0, height], [0, 0]]; var rect = lineBuilder({ data: data, className: 'subject' }); if (type.editMode) { var updateWidth = function updateWidth(attr) { subjectData.width = d3Selection.event.x; type.redrawSubject(); type.redrawConnector(); }; var updateHeight = function updateHeight() { subjectData.height = d3Selection.event.y; type.redrawSubject(); type.redrawConnector(); }; var rHandles = [{ x: width, y: height / 2, drag: updateWidth.bind(type) }, { x: width / 2, y: height, drag: updateHeight.bind(type) }]; handles = type.mapHandles(rHandles); } return { components: [rect], handles: handles }; }); var subjectThreshold = (function (_ref) { var subjectData = _ref.subjectData, type = _ref.type; var offset = type.annotation.position; var x1 = (subjectData.x1 !== undefined ? subjectData.x1 : offset.x) - offset.x, x2 = (subjectData.x2 !== undefined ? subjectData.x2 : offset.x) - offset.x, y1 = (subjectData.y1 !== undefined ? subjectData.y1 : offset.y) - offset.y, y2 = (subjectData.y2 !== undefined ? subjectData.y2 : offset.y) - offset.y; var data = [[x1, y1], [x2, y2]]; return { components: [lineBuilder({ data: data, className: 'subject' })] }; }); var subjectBadge = (function (_ref) { var subjectData = _ref.subjectData, type = _ref.type; if (!subjectData.radius) subjectData.radius = 14; if (!subjectData.x) subjectData.x = "left"; if (!subjectData.y) subjectData.y = "top"; var handles = []; var radius = subjectData.radius; var innerRadius = radius * .7; var x = subjectData.x == "left" ? -radius : radius; var y = subjectData.y == "top" ? -radius : radius; var transform = 'translate(' + x + ', ' + y + ')'; var circlebg = arcBuilder({ className: 'subject', data: { radius: radius } }); circlebg.attrs.transform = transform; var circle = arcBuilder({ className: 'subject-ring', data: { outerRadius: radius, innerRadius: innerRadius } }); circle.attrs.transform = transform; var pointer = lineBuilder({ className: 'subject-pointer', data: [[0, 0], [x, 0], [0, y], [0, 0]] }); if (type.editMode) { var dragBadge = function dragBadge() { subjectData.x = d3Selection.event.x < 0 ? "left" : "right"; subjectData.y = d3Selection.event.y < 0 ? "top" : "bottom"; type.redrawSubject(); }; var bHandles = [{ x: x * 2, y: y * 2, drag: dragBadge.bind(type) }]; handles = type.mapHandles(bHandles); } var text = void 0; if (subjectData.text) { text = { type: "text", className: "badge-text", attrs: { text: subjectData.text, "text-anchor": "middle", dy: ".25em", x: x, y: y } }; } return { components: [pointer, circlebg, circle, text], handles: handles }; }); var Type = function () { function Type(_ref) { var a = _ref.a, annotation = _ref.annotation, editMode = _ref.editMode, dispatcher = _ref.dispatcher, notePadding = _ref.notePadding, accessors = _ref.accessors; classCallCheck(this, Type); this.a = a; this.note = annotation.disable.indexOf("note") === -1 && a.select('g.annotation-note'); this.noteContent = this.note && a.select('g.annotation-note-content'); this.connector = annotation.disable.indexOf("connector") === -1 && a.select('g.annotation-connector'); this.subject = annotation.disable.indexOf("subject") === -1 && a.select('g.annotation-subject'); if (dispatcher) { var handler = addHandlers.bind(null, dispatcher, annotation); handler({ component: this.note, name: 'note' }); handler({ component: this.connector, name: 'connector' }); handler({ component: this.subject, name: 'subject' }); } this.annotation = annotation; this.editMode = annotation.editMode || editMode; this.notePadding = notePadding || 3; this.offsetCornerX = 0; this.offsetCornerY = 0; if (accessors && annotation.data) { this.init(accessors); } } createClass(Type, [{ key: 'init', value: function init(accessors) { if (!this.annotation.x) { this.mapX(accessors); } if (!this.annotation.y) { this.mapY(accessors); } } }, { key: 'mapY', value: function mapY(accessors) { if (accessors.y) { this.annotation.y = accessors.y(this.annotation.data); } } }, { key: 'mapX', value: function mapX(accessors) { if (accessors.x) { this.annotation.x = accessors.x(this.annotation.data); } } }, { key: 'updateEditMode', value: function updateEditMode() { this.a.selectAll('circle.handle').remove(); } }, { key: 'drawOnSVG', value: function drawOnSVG(component, builders) { var _this = this; if (!Array.isArray(builders)) { builders = [builders]; } builders.filter(function (b) { return b; }).forEach(function (_ref2) { var type = _ref2.type, className = _ref2.className, attrs = _ref2.attrs, handles = _ref2.handles; if (type === "handle") { addHandles({ group: component, r: attrs && attrs.r, handles: handles }); } else { (function () { newWithClass(component, [_this.annotation], type, className); var el = component.select(type + '.' + className); var attrKeys = Object.keys(attrs); attrKeys.forEach(function (attr) { if (attr === "text") { el.text(attrs[attr]); } else { el.attr(attr, attrs[attr]); } }); })(); } }); } //TODO: how to extend this to a drawOnCanvas mode? }, { key: 'getNoteBBox', value: function getNoteBBox() { return bboxWithoutHandles(this.note, '.annotation-note-content text'); } }, { key: 'getNoteBBoxOffset', value: function getNoteBBoxOffset() { var bbox = bboxWithoutHandles(this.note, '.annotation-note-content'); var transform = this.noteContent.attr('transform').split(/\(|\,|\)/g); bbox.offsetCornerX = parseFloat(transform[1]) + this.annotation.dx; bbox.offsetCornerY = parseFloat(transform[2]) + this.annotation.dy; bbox.offsetX = this.annotation.dx; bbox.offsetY = this.annotation.dy; return bbox; } // getConnectorBBox() { return bboxWithoutHandles(this.connector)} // getSubjectBBox() { return bboxWithoutHandles(this.subject)} // getAnnotationBBox() { return bboxWithoutHandles(this.a)} }, { key: 'drawSubject', value: function drawSubject() { var context = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var subjectData = this.annotation.subject; var type = context.type; var subjectParams = { type: this, subjectData: subjectData }; var subject = {}; if (type === "circle") subject = subjectCircle(subjectParams);else if (type === "rect") subject = subjectRect(subjectParams);else if (type === "threshold") subject = subjectThreshold(subjectParams);else if (type === "badge") subject = subjectBadge(subjectParams); var _subject = subject, _subject$components = _subject.components, components = _subject$components === undefined ? [] : _subject$components, _subject$handles = _subject.handles, handles = _subject$handles === undefined ? [] : _subject$handles; if (this.editMode) { handles = handles.concat(this.mapHandles([{ drag: this.dragSubject.bind(this) }])); components.push({ type: "handle", handles: handles }); } return components; } }, { key: 'drawConnector', value: function drawConnector() { var context = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var connectorData = this.annotation.connector; var type = connectorData.type || context.type; var connectorParams = { type: this, connectorData: connectorData }; connectorParams.subjectType = this.typeSettings && this.typeSettings.subject && this.typeSettings.subject.type; var connector = {}; if (type === "curve") connector = connectorCurve(connectorParams);else if (type === "elbow") connector = connectorElbow(connectorParams);else connector = connectorLine(connectorParams); var _connector = connector, _connector$components = _connector.components, components = _connector$components === undefined ? [] : _connector$components, _connector$handles = _connector.handles, handles = _connector$handles === undefined ? [] : _connector$handles; var line = components[0]; var endType = connectorData.end || context.end; var end = {}; if (endType === "arrow") end = connectorArrow({ annotation: this.annotation, start: line.data[1], end: line.data[0] });else if (endType === "dot") end = connectorDot({ line: line }); if (end.components) { components = components.concat(end.components); } if (this.editMode) { if (handles.length !== 0) components.push({ type: "handle", handles: handles }); } return components; } }, { key: 'drawNote', value: function drawNote() { var context = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var noteData = this.annotation.note; var align = noteData.align || context.align || 'dynamic'; var noteParams = { bbox: context.bbox, align: align, offset: this.annotation.offset }; var lineType = noteData.lineType || context.lineType; var note = {}; if (lineType == "vertical") note = noteVertical(noteParams);else if (lineType == "horizontal") note = noteHorizontal(noteParams); var _note = note, _note$components = _note.components, components = _note$components === undefined ? [] : _note$components, _note$handles = _note.handles, handles = _note$handles === undefined ? [] : _note$handles; if (this.editMode) { handles = this.mapHandles([{ x: 0, y: 0, drag: this.dragNote.bind(this) }]); components.push({ type: "handle", handles: handles }); } return components; } }, { key: 'drawNoteContent', value: function drawNoteContent(context) { var noteData = this.annotation.note; var padding = noteData.padding || this.notePadding; var orientation = noteData.orientation || context.orientation || 'topBottom'; var lineType = noteData.lineType || context.lineType; var align = noteData.align || context.align || 'dynamic'; var subjectType = this.typeSettings && this.typeSettings.subject && this.typeSettings.subject.type; if (lineType == "vertical") orientation = "leftRight";else if (lineType == "horizontal") orientation = "topBottom"; var noteParams = { padding: padding, bbox: context.bbox, offset: this.annotation.offset, orientation: orientation, align: align }; var _noteAlignment = noteAlignment(noteParams), x = _noteAlignment.x, y = _noteAlignment.y; this.offsetCornerX = x + this.annotation.dx; this.offsetCornerY = y + this.annotation.dy; this.note && this.noteContent.attr('transform', 'translate(' + x + ', ' + y + ')'); return []; } }, { key: 'drawOnScreen', value: function drawOnScreen(component, drawFunction) { return this.drawOnSVG(component, drawFunction); } }, { key: 'redrawSubject', value: function redrawSubject() { this.subject && this.drawOnScreen(this.subject, this.drawSubject()); } }, { key: 'redrawConnector', value: function redrawConnector() { var bbox = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.getNoteBBox(); this.connector && this.drawOnScreen(this.connector, this.drawConnector()); } }, { key: 'redrawNote', value: function redrawNote() { var bbox = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.getNoteBBox(); this.noteContent && this.drawOnScreen(this.noteContent, this.drawNoteContent({ bbox: bbox })); this.note && this.drawOnScreen(this.note, this.drawNote({ bbox: bbox })); } }, { key: 'setPosition', value: function setPosition() { var position = this.annotation.position; this.a.attr('transform', 'translate(' + position.x + ', ' + position.y + ')'); } }, { key: 'setOffset', value: function setOffset() { if (this.note) { var offset = this.annotation.offset; this.note.attr('transform', 'translate(' + offset.x + ', ' + offset.y + ')'); } } }, { key: 'setPositionWithAccessors', value: function setPositionWithAccessors(accessors) { if (accessors && this.annotation.data) { this.mapX(accessors); this.mapY(accessors); } this.setPosition(); } }, { key: 'setClassName', value: function setClassName() { this.a.attr("class", 'annotation ' + (this.className && this.className()) + ' ' + (this.editMode ? "editable" : "") + ' ' + (this.annotation.className || '')); } }, { key: 'draw', value: function draw() { this.setClassName(); this.setPosition(); this.setOffset(); this.redrawSubject(); this.redrawConnector(); this.redrawNote(); } }, { key: 'dragstarted', value: function dragstarted() { d3Selection.event.sourceEvent.stopPropagation(); this.a.classed("dragging", true); this.a.selectAll("circle.handle").style("pointer-events", "none"); } }, { key: 'dragended', value: function dragended() { this.a.classed("dragging", false); this.a.selectAll("circle.handle").style("pointer-events", "all"); } }, { key: 'dragSubject', value: function dragSubject() { var position = this.annotation.position; position.x += d3Selection.event.dx; position.y += d3Selection.event.dy; this.annotation.position = position; } }, { key: 'dragNote', value: function dragNote() { var offset = this.annotation.offset; offset.x += d3Selection.event.dx; offset.y += d3Selection.event.dy; this.annotation.offset = offset; } }, { key: 'mapHandles', value: function mapHandles(handles) { var _this2 = this; return handles.map(function (h) { return _extends({}, h, { start: _this2.dragstarted.bind(_this2), end: _this2.dragended.bind(_this2) }); }); } }]); return Type; }(); var customType = function customType(initialType, typeSettings, _init) { return function (_initialType) { inherits(customType, _initialType); function customType(settings) { classCallCheck(this, customType); var _this3 = possibleConstructorReturn(this, (customType.__proto__ || Object.getPrototypeOf(customType)).call(this, settings)); _this3.typeSettings = typeSettings; if (typeSettings.disable) { typeSettings.disable.forEach(function (d) { _this3[d] = undefined; if (d == "note") { _this3.noteContent = undefined; } }); } return _this3; } createClass(customType, [{ key: 'className', value: function className() { return (typeSettings.className || '') + ' ' + (get(customType.prototype.__proto__ || Object.getPrototypeOf(customType.prototype), 'className', this) && get(customType.prototype.__proto__ || Object.getPrototypeOf(customType.prototype), 'className', this).call(this) || ''); } }, { key: 'drawSubject', value: function drawSubject(context) { this.typeSettings.subject = Object.assign({}, typeSettings.subject, this.typeSettings.subject); return get(customType.prototype.__proto__ || Object.getPrototypeOf(customType.prototype), 'drawSubject', this).call(this, _extends({}, context, this.typeSettings.subject)); } }, { key: 'drawConnector', value: function drawConnector(context, subjectContext) { this.typeSettings.connector = Object.assign({}, typeSettings.connector, this.typeSettings.connector); return get(customType.prototype.__proto__ || Object.getPrototypeOf(customType.prototype), 'drawConnector', this).call(this, _extends({}, context, typeSettings.connector, this.typeSettings.connector)); } }, { key: 'drawNote', value: function drawNote(context) { this.typeSettings.note = Object.assign({}, typeSettings.note, this.typeSettings.note); return get(customType.prototype.__proto__ || Object.getPrototypeOf(customType.prototype), 'drawNote', this).call(this, _extends({}, context, typeSettings.note, this.typeSettings.note)); } }, { key: 'drawNoteContent', value: function drawNoteContent(context) { return get(customType.prototype.__proto__ || Object.getPrototypeOf(customType.prototype), 'drawNoteContent', this).call(this, _extends({}, context, typeSettings.note, this.typeSettings.note)); } }], [{ key: 'init', value: function init(annotation, accessors) { get(customType.__proto__ || Object.getPrototypeOf(customType), 'init', this).call(this, annotation, accessors); if (_init) { annotation = _init(annotation, accessors); } return annotation; } }]); return customType; }(initialType); }; var d3NoteText = function (_Type) { inherits(d3NoteText, _Type); function d3NoteText(params) { classCallCheck(this, d3NoteText); var _this4 = possibleConstructorReturn(this, (d3NoteText.__proto__ || Object.getPrototypeOf(d3NoteText)).call(this, params)); console.log('in constructor for note text', params, _this4.typeSettings); _this4.textWrap = params.textWrap || 120; _this4.drawText(); return _this4; } createClass(d3NoteText, [{ key: 'updateTextWrap', value: function updateTextWrap(textWrap) { this.textWrap = textWrap; this.drawText(); } //TODO: add update text functionality }, { key: 'drawText', value: function drawText() { if (this.note) { newWithClass(this.note, [this.annotation], 'g', 'annotation-note-content'); var noteContent = this.note.select('g.annotation-note-content'); newWithClass(noteContent, [this.annotation], 'rect', 'annotation-note-bg'); newWithClass(noteContent, [this.annotation], 'text', 'annotation-note-label'); newWithClass(noteContent, [this.annotation], 'text', 'annotation-note-title'); var titleBBox = { height: 0 }; var label = this.a.select('text.annotation-note-label'); console.log('in wrap length', this.typeSettings); var wrapLength = this.annotation.note && this.annotation.note.wrap || this.typeSettings && this.typeSettings.note && this.typeSettings.note.wrap || this.textWrap; if (this.annotation.note.title) { var title = this.a.select('text.annotation-note-title'); title.text(this.annotation.note.title).attr('dy', '1.1em'); title.call(wrap, wrapLength); titleBBox = title.node().getBBox(); } label.text(this.annotation.note.label).attr('dy', '1em'); label.call(wrap, wrapLength); label.attr('y', titleBBox.height * 1.1 || 0); var bbox = this.getNoteBBox(); this.a.select('rect.annotation-note-bg').attr('width', bbox.width).attr('height', bbox.height); } } }]); return d3NoteText; }(Type); var d3Label = customType(d3NoteText, { className: "label", note: { align: "middle" } }); var d3Callout = customType(d3NoteText, { className: "callout", note: { lineType: "horizontal" } }); var d3CalloutElbow = customType(d3Callout, { className: "callout elbow", connector: { type: "elbow" } }); var d3CalloutCurve = customType(d3Callout, { className: "callout curve", connector: { type: "curve" } }); var d3Badge = customType(Type, { className: "badge", subject: { type: "badge" }, disable: ['connector', 'note'] }); var d3CalloutCircle = customType(d3CalloutElbow, { className: "callout circle", subject: { type: "circle" } }); var d3CalloutRect = customType(d3CalloutElbow, { className: "callout rect", subject: { type: "rect" } }); var ThresholdMap = function (_d3Callout) { inherits(ThresholdMap, _d3Callout); function ThresholdMap() { classCallCheck(this, ThresholdMap); return possibleConstructorReturn(this, (Thre