diff options
Diffstat (limited to 'src')
34 files changed, 274 insertions, 214 deletions
diff --git a/src/animation/Runner.js b/src/animation/Runner.js index 8c0aca5..8c56423 100644 --- a/src/animation/Runner.js +++ b/src/animation/Runner.js @@ -681,7 +681,7 @@ extend(Runner, { }, zoom (level, point) { - if (this._tryRetarget('zoom', to, point)) return this + if (this._tryRetarget('zoom', level, point)) return this var morpher = new Morphable(this._stepper).to(new SVGNumber(level)) diff --git a/src/elements/A.js b/src/elements/A.js index 4e7297b..6f9bec2 100644 --- a/src/elements/A.js +++ b/src/elements/A.js @@ -4,8 +4,8 @@ import { xlink } from '../modules/core/namespaces.js' import Container from './Container.js' export default class A extends Container { - constructor (node) { - super(nodeOrNew('a', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('a', node), attrs) } // Link url @@ -27,9 +27,31 @@ registerMethods({ }) }, Element: { - // Create a hyperlink element - linkTo: function (url) { - var link = new A() + unlink () { + var link = this.linker() + + if (!link) return this + + var parent = link.parent() + + if (!parent) { + return this.remove() + } + + var index = parent.index(link) + parent.add(this, index) + + link.remove() + return this + }, + linkTo (url) { + // reuse old link if possible + var link = this.linker() + + if (!link) { + link = new A() + this.wrap(link) + } if (typeof url === 'function') { url.call(link, link) @@ -37,7 +59,15 @@ registerMethods({ link.to(url) } - return this.parent().put(link).put(this) + return this + }, + linker () { + var link = this.parent() + if (link && link.node.nodeName.toLowerCase() === 'a') { + return link + } + + return null } } }) diff --git a/src/elements/Circle.js b/src/elements/Circle.js index 29683c9..701b5e1 100644 --- a/src/elements/Circle.js +++ b/src/elements/Circle.js @@ -10,8 +10,8 @@ import SVGNumber from '../types/SVGNumber.js' import Shape from './Shape.js' export default class Circle extends Shape { - constructor (node) { - super(nodeOrNew('circle', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('circle', node), attrs) } radius (r) { diff --git a/src/elements/ClipPath.js b/src/elements/ClipPath.js index 0a87bed..55f9c3d 100644 --- a/src/elements/ClipPath.js +++ b/src/elements/ClipPath.js @@ -4,8 +4,8 @@ import Container from './Container.js' import baseFind from '../modules/core/selector.js' export default class ClipPath extends Container { - constructor (node) { - super(nodeOrNew('clipPath', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('clipPath', node), attrs) } // Unclip all clipped elements and remove itself diff --git a/src/elements/Defs.js b/src/elements/Defs.js index 1bd3bd4..7491ba0 100644 --- a/src/elements/Defs.js +++ b/src/elements/Defs.js @@ -2,8 +2,8 @@ import { nodeOrNew, register } from '../utils/adopter.js' import Container from './Container.js' export default class Defs extends Container { - constructor (node) { - super(nodeOrNew('defs', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('defs', node), attrs) } flatten () { diff --git a/src/elements/Dom.js b/src/elements/Dom.js index 0c4ecb3..6fd1b1b 100644 --- a/src/elements/Dom.js +++ b/src/elements/Dom.js @@ -194,22 +194,15 @@ export default class Dom extends EventTarget { return element } - round (precision = 2, map) { + round (precision = 2, map = null) { const factor = 10 ** precision - const attrs = this.attr() + const attrs = this.attr(map) - // If we have no map, build one from attrs - if (!map) { - map = Object.keys(attrs) + for (const i in attrs) { + attrs[i] = Math.round(attrs[i] * factor) / factor } - // Holds rounded attributes - const newAttrs = {} - map.forEach((key) => { - newAttrs[key] = Math.round(attrs[key] * factor) / factor - }) - - this.attr(newAttrs) + this.attr(attrs) return this } @@ -302,6 +295,17 @@ export default class Dom extends EventTarget { return this } + wrap (node) { + const parent = this.parent() + + if (!parent) { + return node.put(this) + } + + const position = parent.index(this) + return parent.put(node, position).put(this) + } + // write svgjs data to the dom writeDataToDom () { // dump variables recursively diff --git a/src/elements/Element.js b/src/elements/Element.js index 3bd97de..56dbcf3 100644 --- a/src/elements/Element.js +++ b/src/elements/Element.js @@ -38,7 +38,9 @@ export default class Element extends Dom { // Move by center over x-axis cx (x) { - return x == null ? this.x() + this.width() / 2 : this.x(x - this.width() / 2) + return x == null + ? this.x() + this.width() / 2 + : this.x(x - this.width() / 2) } // Move by center over y-axis @@ -99,17 +101,16 @@ export default class Element extends Dom { } // return array of all ancestors of given type up to the root svg - parents (until = globals.document) { + parents (until = this.root()) { until = makeInstance(until) const parents = new List() let parent = this - while ( - (parent = parent.parent()) - && parent.node !== until.node - && parent.node !== globals.document - ) { + while ((parent = parent.parent()) && parent.node !== globals.document) { parents.push(parent) + if (parent.node === until.node) { + break + } } return parents diff --git a/src/elements/Ellipse.js b/src/elements/Ellipse.js index 60660e7..b993687 100644 --- a/src/elements/Ellipse.js +++ b/src/elements/Ellipse.js @@ -11,8 +11,8 @@ import Shape from './Shape.js' import * as circled from '../modules/core/circled.js' export default class Ellipse extends Shape { - constructor (node) { - super(nodeOrNew('ellipse', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('ellipse', node), attrs) } size (width, height) { diff --git a/src/elements/ForeignObject.js b/src/elements/ForeignObject.js index 4e6aae4..0a417b0 100644 --- a/src/elements/ForeignObject.js +++ b/src/elements/ForeignObject.js @@ -3,8 +3,8 @@ import { registerMethods } from '../utils/methods.js' import Element from './Element.js' export default class ForeignObject extends Element { - constructor (node) { - super(nodeOrNew('foreignObject', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('foreignObject', node), attrs) } } diff --git a/src/elements/G.js b/src/elements/G.js index d922a41..7677b92 100644 --- a/src/elements/G.js +++ b/src/elements/G.js @@ -6,8 +6,8 @@ import Matrix from '../types/Matrix.js' import Point from '../types/Point.js' export default class G extends Container { - constructor (node) { - super(nodeOrNew('g', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('g', node), attrs) } x (x, box = this.bbox()) { diff --git a/src/elements/Image.js b/src/elements/Image.js index fdd3d83..347269c 100644 --- a/src/elements/Image.js +++ b/src/elements/Image.js @@ -9,8 +9,8 @@ import Shape from './Shape.js' import { globals } from '../utils/window.js' export default class Image extends Shape { - constructor (node) { - super(nodeOrNew('image', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('image', node), attrs) } // (re)load image diff --git a/src/elements/Line.js b/src/elements/Line.js index 0b7534b..146aa45 100644 --- a/src/elements/Line.js +++ b/src/elements/Line.js @@ -12,8 +12,8 @@ import * as pointed from '../modules/core/pointed.js' export default class Line extends Shape { // Initialize node - constructor (node) { - super(nodeOrNew('line', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('line', node), attrs) } // Get array diff --git a/src/elements/Marker.js b/src/elements/Marker.js index d6a599d..b3077b1 100644 --- a/src/elements/Marker.js +++ b/src/elements/Marker.js @@ -4,8 +4,8 @@ import Container from './Container.js' export default class Marker extends Container { // Initialize node - constructor (node) { - super(nodeOrNew('marker', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('marker', node), attrs) } // Set width of element @@ -18,6 +18,10 @@ export default class Marker extends Container { return this.attr('markerHeight', height) } + orient (orient) { + return this.attr('orient', orient) + } + // Set marker refX and refY ref (x, y) { return this.attr('refX', x).attr('refY', y) diff --git a/src/elements/Mask.js b/src/elements/Mask.js index 178dcb5..64caca5 100644 --- a/src/elements/Mask.js +++ b/src/elements/Mask.js @@ -5,8 +5,8 @@ import baseFind from '../modules/core/selector.js' export default class Mask extends Container { // Initialize node - constructor (node) { - super(nodeOrNew('mask', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('mask', node), attrs) } // Unmask all masked elements and remove itself diff --git a/src/elements/Path.js b/src/elements/Path.js index 4549506..8f37319 100644 --- a/src/elements/Path.js +++ b/src/elements/Path.js @@ -7,8 +7,8 @@ import baseFind from '../modules/core/selector.js' export default class Path extends Shape { // Initialize node - constructor (node) { - super(nodeOrNew('path', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('path', node), attrs) } // Get array diff --git a/src/elements/Pattern.js b/src/elements/Pattern.js index 99e8ded..72b7c59 100644 --- a/src/elements/Pattern.js +++ b/src/elements/Pattern.js @@ -6,8 +6,8 @@ import baseFind from '../modules/core/selector.js' export default class Pattern extends Container { // Initialize node - constructor (node) { - super(nodeOrNew('pattern', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('pattern', node), attrs) } // Return the fill id diff --git a/src/elements/Polygon.js b/src/elements/Polygon.js index 5984689..0c99aa7 100644 --- a/src/elements/Polygon.js +++ b/src/elements/Polygon.js @@ -12,8 +12,8 @@ import * as poly from '../modules/core/poly.js' export default class Polygon extends Shape { // Initialize node - constructor (node) { - super(nodeOrNew('polygon', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('polygon', node), attrs) } } diff --git a/src/elements/Polyline.js b/src/elements/Polyline.js index 94a767c..e390da3 100644 --- a/src/elements/Polyline.js +++ b/src/elements/Polyline.js @@ -12,8 +12,8 @@ import * as poly from '../modules/core/poly.js' export default class Polyline extends Shape { // Initialize node - constructor (node) { - super(nodeOrNew('polyline', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('polyline', node), attrs) } } diff --git a/src/elements/Rect.js b/src/elements/Rect.js index 149ae48..0ed85fc 100644 --- a/src/elements/Rect.js +++ b/src/elements/Rect.js @@ -10,8 +10,8 @@ import Shape from './Shape.js' export default class Rect extends Shape { // Initialize node - constructor (node) { - super(nodeOrNew('rect', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('rect', node), attrs) } } diff --git a/src/elements/Stop.js b/src/elements/Stop.js index 570dda7..d258b86 100644 --- a/src/elements/Stop.js +++ b/src/elements/Stop.js @@ -3,8 +3,8 @@ import Element from './Element.js' import SVGNumber from '../types/SVGNumber.js' export default class Stop extends Element { - constructor (node) { - super(nodeOrNew('stop', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('stop', node), attrs) } // add color stops diff --git a/src/elements/Style.js b/src/elements/Style.js index b878189..0b7d952 100644 --- a/src/elements/Style.js +++ b/src/elements/Style.js @@ -19,8 +19,8 @@ function cssRule (selector, rule) { } export default class Style extends Element { - constructor (node) { - super(nodeOrNew('style', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('style', node), attrs) } addText (w = '') { diff --git a/src/elements/Svg.js b/src/elements/Svg.js index f96a5f8..7cec826 100644 --- a/src/elements/Svg.js +++ b/src/elements/Svg.js @@ -11,8 +11,8 @@ import Defs from './Defs.js' import { globals } from '../utils/window.js' export default class Svg extends Container { - constructor (node) { - super(nodeOrNew('svg', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('svg', node), attrs) this.namespace() } diff --git a/src/elements/Symbol.js b/src/elements/Symbol.js index 3dd48d7..d2a98ac 100644 --- a/src/elements/Symbol.js +++ b/src/elements/Symbol.js @@ -4,8 +4,8 @@ import Container from './Container.js' export default class Symbol extends Container { // Initialize node - constructor (node) { - super(nodeOrNew('symbol', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('symbol', node), attrs) } } diff --git a/src/elements/Text.js b/src/elements/Text.js index b3fb8e0..2951c2f 100644 --- a/src/elements/Text.js +++ b/src/elements/Text.js @@ -13,60 +13,14 @@ import * as textable from '../modules/core/textable.js' export default class Text extends Shape { // Initialize node - constructor (node) { - super(nodeOrNew('text', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('text', node), attrs) this.dom.leading = new SVGNumber(1.3) // store leading value for rebuilding this._rebuild = true // enable automatic updating of dy values this._build = false // disable build mode for adding multiple lines } - // Move over x-axis - // Text is moved its bounding box - // text-anchor does NOT matter - x (x, box = this.bbox()) { - if (x == null) { - return box.x - } - - return this.attr('x', this.attr('x') + x - box.x) - } - - // Move over y-axis - y (y, box = this.bbox()) { - if (y == null) { - return box.y - } - - return this.attr('y', this.attr('y') + y - box.y) - } - - move (x, y, box = this.bbox()) { - return this.x(x, box).y(y, box) - } - - // Move center over x-axis - cx (x, box = this.bbox()) { - if (x == null) { - return box.cx - } - - return this.attr('x', this.attr('x') + x - box.cx) - } - - // Move center over y-axis - cy (y, box = this.bbox()) { - if (y == null) { - return box.cy - } - - return this.attr('y', this.attr('y') + y - box.cy) - } - - center (x, y, box = this.bbox()) { - return this.cx(x, box).cy(y, box) - } - // Set the text content text (text) { // act as getter @@ -102,11 +56,11 @@ export default class Text extends Shape { text.call(this, this) } else { // store text and make sure text is not blank - text = text.split('\n') + text = (text + '').split('\n') // build new lines for (var j = 0, jl = text.length; j < jl; j++) { - this.tspan(text[j]).newLine() + this.newLine(text[j]) } } @@ -140,9 +94,10 @@ export default class Text extends Shape { var blankLineOffset = 0 var leading = this.dom.leading - this.each(function () { + this.each(function (i) { var fontSize = globals.window.getComputedStyle(this.node) .getPropertyValue('font-size') + var dy = leading * new SVGNumber(fontSize) if (this.dom.newLined) { @@ -151,7 +106,7 @@ export default class Text extends Shape { if (this.text() === '\n') { blankLineOffset += dy } else { - this.attr('dy', dy + blankLineOffset) + this.attr('dy', i ? dy + blankLineOffset : 0) blankLineOffset = 0 } } @@ -163,12 +118,6 @@ export default class Text extends Shape { return this } - // Enable / disable build mode - build (build) { - this._build = !!build - return this - } - // overwrite method from parent to set data properly setData (o) { this.dom = o @@ -182,12 +131,12 @@ extend(Text, textable) registerMethods({ Container: { // Create text element - text: wrapWithAttrCheck(function (text) { + text: wrapWithAttrCheck(function (text = '') { return this.put(new Text()).text(text) }), // Create plain text element - plain: wrapWithAttrCheck(function (text) { + plain: wrapWithAttrCheck(function (text = '') { return this.put(new Text()).plain(text) }) } diff --git a/src/elements/TextPath.js b/src/elements/TextPath.js index f26b251..fde8131 100644 --- a/src/elements/TextPath.js +++ b/src/elements/TextPath.js @@ -8,8 +8,8 @@ import baseFind from '../modules/core/selector.js' export default class TextPath extends Text { // Initialize node - constructor (node) { - super(nodeOrNew('textPath', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('textPath', node), attrs) } // return the array of the path track element @@ -92,7 +92,7 @@ registerMethods({ }), targets () { - return baseFind('svg [href*="' + this.id() + '"]') + return baseFind('svg [*|href*="' + this.id() + '"]') } } }) diff --git a/src/elements/Tspan.js b/src/elements/Tspan.js index 11f7fc3..00934ab 100644 --- a/src/elements/Tspan.js +++ b/src/elements/Tspan.js @@ -7,20 +7,28 @@ import { import { globals } from '../utils/window.js' import { registerMethods } from '../utils/methods.js' import SVGNumber from '../types/SVGNumber.js' +import Shape from './Shape.js' import Text from './Text.js' import * as textable from '../modules/core/textable.js' -export default class Tspan extends Text { +export default class Tspan extends Shape { // Initialize node - constructor (node) { - super(nodeOrNew('tspan', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('tspan', node), attrs) + this._build = false // disable build mode for adding multiple lines } // Set text content text (text) { if (text == null) return this.node.textContent + (this.dom.newLined ? '\n' : '') - typeof text === 'function' ? text.call(this, this) : this.plain(text) + if (typeof text === 'function') { + this.clear().build(true) + text.call(this, this) + this.build(false) + } else { + this.plain(text) + } return this } @@ -35,32 +43,27 @@ export default class Tspan extends Text { return this.attr('dy', dy) } - x (x) { - return this.attr('x', x) - } - - y (y) { - return this.attr('x', y) - } - - move (x, y) { - return this.x(x).y(y) - } - // Create new line newLine () { - // fetch text parent - var t = this.parent(Text) - // mark new line this.dom.newLined = true + // fetch parent + var text = this.parent() + + // early return in case we are not in a text element + if (!(text instanceof Text)) { + return this + } + + var i = text.index(this) + var fontSize = globals.window.getComputedStyle(this.node) .getPropertyValue('font-size') - var dy = t.dom.leading * new SVGNumber(fontSize) + var dy = text.dom.leading * new SVGNumber(fontSize) // apply new position - return this.dy(dy).attr('x', t.x()) + return this.dy(i ? dy : 0).attr('x', text.x()) } } @@ -68,7 +71,7 @@ extend(Tspan, textable) registerMethods({ Tspan: { - tspan: wrapWithAttrCheck(function (text) { + tspan: wrapWithAttrCheck(function (text = '') { var tspan = new Tspan() // clear if build mode is disabled @@ -77,10 +80,13 @@ registerMethods({ } // add new tspan - this.node.appendChild(tspan.node) - - return tspan.text(text) + return this.put(tspan).text(text) }) + }, + Text: { + newLine: function (text = '') { + return this.tspan(text).newLine() + } } }) diff --git a/src/elements/Use.js b/src/elements/Use.js index 99fb8ec..30d9436 100644 --- a/src/elements/Use.js +++ b/src/elements/Use.js @@ -4,12 +4,12 @@ import { xlink } from '../modules/core/namespaces.js' import Shape from './Shape.js' export default class Use extends Shape { - constructor (node) { - super(nodeOrNew('use', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('use', node), attrs) } // Use element as a reference - element (element, file) { + use (element, file) { // Set lined element return this.attr('href', (file || '') + '#' + element, xlink) } @@ -19,7 +19,7 @@ registerMethods({ Container: { // Create a use element use: wrapWithAttrCheck(function (element, file) { - return this.put(new Use()).element(element, file) + return this.put(new Use()).use(element, file) }) } }) diff --git a/src/modules/core/event.js b/src/modules/core/event.js index 2cf9b1e..976e13d 100644 --- a/src/modules/core/event.js +++ b/src/modules/core/event.js @@ -3,9 +3,9 @@ import { makeInstance } from '../../utils/adopter.js' import { globals } from '../../utils/window.js' let listenerId = 0 -const windowEvents = {} +export const windowEvents = {} -function getEvents (instance) { +export function getEvents (instance) { let n = instance.getEventHolder() // We dont want to save events in global space @@ -14,12 +14,13 @@ function getEvents (instance) { return n.events } -function getEventTarget (instance) { +export function getEventTarget (instance) { return instance.getEventTarget() } -function clearEvents (instance) { - const n = instance.getEventHolder() +export function clearEvents (instance) { + let n = instance.getEventHolder() + if (n === globals.window) n = windowEvents if (n.events) n.events = {} } @@ -120,14 +121,14 @@ export function off (node, events, listener, options) { }) } -export function dispatch (node, event, data) { +export function dispatch (node, event, data, options) { var n = getEventTarget(node) // Dispatch event if (event instanceof globals.window.Event) { n.dispatchEvent(event) } else { - event = new globals.window.CustomEvent(event, { detail: data, cancelable: true }) + event = new globals.window.CustomEvent(event, { detail: data, cancelable: true, ...options }) n.dispatchEvent(event) } return event diff --git a/src/modules/core/textable.js b/src/modules/core/textable.js index 55df7c6..28b13cb 100644 --- a/src/modules/core/textable.js +++ b/src/modules/core/textable.js @@ -17,3 +17,67 @@ export function plain (text) { export function length () { return this.node.getComputedTextLength() } + +// Move over x-axis +// Text is moved by its bounding box +// text-anchor does NOT matter +export function x (x, box = this.bbox()) { + if (x == null) { + return box.x + } + + return this.attr('x', this.attr('x') + x - box.x) +} + +// Move over y-axis +export function y (y, box = this.bbox()) { + if (y == null) { + return box.y + } + + return this.attr('y', this.attr('y') + y - box.y) +} + +export function move (x, y, box = this.bbox()) { + return this.x(x, box).y(y, box) +} + +// Move center over x-axis +export function cx (x, box = this.bbox()) { + if (x == null) { + return box.cx + } + + return this.attr('x', this.attr('x') + x - box.cx) +} + +// Move center over y-axis +export function cy (y, box = this.bbox()) { + if (y == null) { + return box.cy + } + + return this.attr('y', this.attr('y') + y - box.cy) +} + +export function center (x, y, box = this.bbox()) { + return this.cx(x, box).cy(y, box) +} + +export function ax (x) { + return this.attr('x', x) +} + +export function ay (y) { + return this.attr('y', y) +} + +export function amove (x, y) { + return this.ax(x).ay(y) +} + +// Enable / disable build mode +export function build (build) { + this._build = !!build + return this +} diff --git a/src/modules/optional/sugar.js b/src/modules/optional/sugar.js index 0da0fe4..0de2c04 100644 --- a/src/modules/optional/sugar.js +++ b/src/modules/optional/sugar.js @@ -87,16 +87,13 @@ registerMethods([ 'Element', 'Runner' ], { }, // Map flip to transform - flip: function (direction, around) { - var directionString = typeof direction === 'string' ? direction - : isFinite(direction) ? 'both' - : 'both' - var origin = (direction === 'both' && isFinite(around)) ? [ around, around ] - : (direction === 'x') ? [ around, 0 ] - : (direction === 'y') ? [ 0, around ] - : isFinite(direction) ? [ direction, direction ] - : [ 0, 0 ] - return this.transform({ flip: directionString, origin: origin }, true) + flip: function (direction = 'both', origin = 'center') { + if ('xybothtrue'.indexOf(direction) === -1) { + origin = direction + direction = 'both' + } + + return this.transform({ flip: direction, origin: origin }, true) }, // Opacity @@ -144,18 +141,6 @@ registerMethods([ 'Element', 'Runner' ], { } }) -registerMethods('Text', { - ax (x) { - return this.attr('x', x) - }, - ay (y) { - return this.attr('y', y) - }, - amove (x, y) { - return this.ax(x).ay(y) - } -}) - // Add events to elements const methods = [ 'click', 'dblclick', @@ -2,8 +2,8 @@ import * as svgMembers from './main.js' import { makeInstance } from './utils/adopter.js' // The main wrapping element -export default function SVG (element) { - return makeInstance(element) +export default function SVG (element, isHTML) { + return makeInstance(element, isHTML) } Object.assign(SVG, svgMembers) diff --git a/src/types/Box.js b/src/types/Box.js index 5c31535..6d7d8a9 100644 --- a/src/types/Box.js +++ b/src/types/Box.js @@ -95,7 +95,7 @@ export default class Box { // offset by window scroll position, because getBoundingClientRect changes when window is scrolled this.x += globals.window.pageXOffset this.y += globals.window.pageYOffset - return this + return new Box(this) } toString () { @@ -166,7 +166,7 @@ registerMethods({ // Firefox does not support clientHeight and returns 0 // https://bugzilla.mozilla.org/show_bug.cgi?id=874811 if (!width && !height) { - var style = window.getComputedStyle(this.node) + var style = globals.window.getComputedStyle(this.node) width = parseFloat(style.getPropertyValue('width')) height = parseFloat(style.getPropertyValue('height')) } diff --git a/src/utils/adopter.js b/src/utils/adopter.js index e8b30ea..30eab84 100644 --- a/src/utils/adopter.js +++ b/src/utils/adopter.js @@ -13,7 +13,7 @@ export function create (name) { return globals.document.createElementNS(ns, name) } -export function makeInstance (element) { +export function makeInstance (element, isHTML = false) { if (element instanceof Base) return element if (typeof element === 'object') { @@ -28,7 +28,8 @@ export function makeInstance (element) { return adopter(globals.document.querySelector(element)) } - var node = create('svg') + // Make sure, that HTML elements are created with the correct namespace + var node = isHTML ? globals.document.createElement('div') : create('svg') node.innerHTML = element // We can use firstChild here because we know, diff --git a/src/utils/utils.js b/src/utils/utils.js index 5d8706e..ee47079 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -43,7 +43,7 @@ export function camelCase (s) { }) } -// Convert camel cased string to string seperated +// Convert camel cased string to dash seperated export function unCamelCase (s) { return s.replace(/([A-Z])/g, function (m, g) { return '-' + g.toLowerCase() @@ -73,31 +73,46 @@ export function proportionalSize (element, width, height, box) { } } +/** + * This function adds support for string origins. + * It searches for an origin in o.origin o.ox and o.originX. + * This way, origin: {x: 'center', y: 50} can be passed as well as ox: 'center', oy: 50 +**/ export function getOrigin (o, element) { - // Allow origin or around as the names - const origin = o.origin // o.around == null ? o.origin : o.around - let ox, oy - - // Allow the user to pass a string to rotate around a given point - if (typeof origin === 'string' || origin == null) { - // Get the bounding box of the element with no transformations applied - const string = (origin || 'center').toLowerCase().trim() + const origin = o.origin + // First check if origin is in ox or originX + let ox = o.ox != null ? o.ox + : o.originX != null ? o.originX + : 'center' + let oy = o.oy != null ? o.oy + : o.originY != null ? o.originY + : 'center' + + // Then check if origin was used and overwrite in that case + if (origin != null) { + [ ox, oy ] = Array.isArray(origin) ? origin + : typeof origin === 'object' ? [ origin.x, origin.y ] + : [ origin, origin ] + } + + // Make sure to only call bbox when actually needed + const condX = typeof ox === 'string' + const condY = typeof oy === 'string' + if (condX || condY) { const { height, width, x, y } = element.bbox() - // Calculate the transformed x and y coordinates - const bx = string.includes('left') ? x - : string.includes('right') ? x + width - : x + width / 2 - const by = string.includes('top') ? y - : string.includes('bottom') ? y + height - : y + height / 2 - - // Set the bounds eg : "bottom-left", "Top right", "middle" etc... - ox = o.ox != null ? o.ox : bx - oy = o.oy != null ? o.oy : by - } else { - ox = origin[0] - oy = origin[1] + // And only overwrite if string was passed for this specific axis + if (condX) { + ox = ox.includes('left') ? x + : ox.includes('right') ? x + width + : x + width / 2 + } + + if (condY) { + oy = oy.includes('top') ? y + : oy.includes('bottom') ? y + height + : y + height / 2 + } } // Return the origin as it is if it wasn't a string |