summaryrefslogtreecommitdiffstats
path: root/src/elements/Text.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/elements/Text.js')
-rw-r--r--src/elements/Text.js177
1 files changed, 177 insertions, 0 deletions
diff --git a/src/elements/Text.js b/src/elements/Text.js
new file mode 100644
index 0000000..58d50a3
--- /dev/null
+++ b/src/elements/Text.js
@@ -0,0 +1,177 @@
+import { adopt, extend, nodeOrNew, register } from '../utils/adopter.js'
+import { attrs } from '../modules/core/defaults.js'
+import { registerMethods } from '../utils/methods.js'
+import SVGNumber from '../types/SVGNumber.js'
+import Shape from './Shape.js'
+import * as textable from '../modules/core/textable.js'
+
+export default class Text extends Shape {
+ // Initialize node
+ constructor (node) {
+ super(nodeOrNew('text', node), Text)
+
+ 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
+
+ // set default font
+ this.attr('font-family', attrs['font-family'])
+ }
+
+ // Move over x-axis
+ x (x) {
+ // act as getter
+ if (x == null) {
+ return this.attr('x')
+ }
+
+ return this.attr('x', x)
+ }
+
+ // Move over y-axis
+ y (y) {
+ var oy = this.attr('y')
+ var o = typeof oy === 'number' ? oy - this.bbox().y : 0
+
+ // act as getter
+ if (y == null) {
+ return typeof oy === 'number' ? oy - o : oy
+ }
+
+ return this.attr('y', typeof y === 'number' ? y + o : y)
+ }
+
+ // Move center over x-axis
+ cx (x) {
+ return x == null ? this.bbox().cx : this.x(x - this.bbox().width / 2)
+ }
+
+ // Move center over y-axis
+ cy (y) {
+ return y == null ? this.bbox().cy : this.y(y - this.bbox().height / 2)
+ }
+
+ // Set the text content
+ text (text) {
+ // act as getter
+ if (text === undefined) {
+ // FIXME use children() or each()
+ var children = this.node.childNodes
+ var firstLine = 0
+ text = ''
+
+ for (var i = 0, len = children.length; i < len; ++i) {
+ // skip textPaths - they are no lines
+ if (children[i].nodeName === 'textPath') {
+ if (i === 0) firstLine = 1
+ continue
+ }
+
+ // add newline if its not the first child and newLined is set to true
+ if (i !== firstLine && children[i].nodeType !== 3 && adopt(children[i]).dom.newLined === true) {
+ text += '\n'
+ }
+
+ // add content of this node
+ text += children[i].textContent
+ }
+
+ return text
+ }
+
+ // remove existing content
+ this.clear().build(true)
+
+ if (typeof text === 'function') {
+ // call block
+ text.call(this, this)
+ } else {
+ // store text and make sure text is not blank
+ text = text.split('\n')
+
+ // build new lines
+ for (var j = 0, jl = text.length; j < jl; j++) {
+ this.tspan(text[j]).newLine()
+ }
+ }
+
+ // disable build mode and rebuild lines
+ return this.build(false).rebuild()
+ }
+
+ // Set / get leading
+ leading (value) {
+ // act as getter
+ if (value == null) {
+ return this.dom.leading
+ }
+
+ // act as setter
+ this.dom.leading = new SVGNumber(value)
+
+ return this.rebuild()
+ }
+
+ // Rebuild appearance type
+ rebuild (rebuild) {
+ // store new rebuild flag if given
+ if (typeof rebuild === 'boolean') {
+ this._rebuild = rebuild
+ }
+
+ // define position of all lines
+ if (this._rebuild) {
+ var self = this
+ var blankLineOffset = 0
+ var dy = this.dom.leading * new SVGNumber(this.attr('font-size'))
+
+ this.each(function () {
+ if (this.dom.newLined) {
+ this.attr('x', self.attr('x'))
+
+ if (this.text() === '\n') {
+ blankLineOffset += dy
+ } else {
+ this.attr('dy', dy + blankLineOffset)
+ blankLineOffset = 0
+ }
+ }
+ })
+
+ this.fire('rebuild')
+ }
+
+ 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
+ this.dom.leading = new SVGNumber(o.leading || 1.3)
+ return this
+ }
+}
+
+extend(Text, textable)
+
+registerMethods({
+ Container: {
+ // Create text element
+ text (text) {
+ return this.put(new Text()).text(text)
+ },
+
+ // Create plain text element
+ plain (text) {
+ return this.put(new Text()).plain(text)
+ }
+ }
+})
+
+register(Text)