249 lines
9.3 KiB
CoffeeScript
249 lines
9.3 KiB
CoffeeScript
# A text in the whiteboard
|
|
class @WhiteboardTextModel extends WhiteboardToolModel
|
|
|
|
constructor: (@paper) ->
|
|
super @paper
|
|
# the defintion of this shape, kept so we can redraw the shape whenever needed
|
|
# format: x, y, width, height, colour, fontSize, calcFontSize, text
|
|
@definition = [0, 0, 0, 0, "#000", 0, 0, ""]
|
|
|
|
# Make a text on the whiteboard
|
|
make: (startingData) ->
|
|
#console.log "making text:" + JSON.stringify startingData
|
|
|
|
x = startingData.x
|
|
y = startingData.y
|
|
width = startingData.textBoxWidth
|
|
height = startingData.textBoxHeight
|
|
colour = startingData.fontColor
|
|
fontSize = startingData.fontSize
|
|
calcFontSize = startingData.calcedFontSize
|
|
text = startingData.text
|
|
|
|
@definition =
|
|
shape: "text"
|
|
data: [x, y, width, height, colour, fontSize, calcFontSize, text]
|
|
|
|
#calcFontSize = (calcFontSize/100 * @gh)
|
|
x = (x * @gw) + @xOffset
|
|
y = (y * @gh) + @yOffset + calcFontSize
|
|
width = width/100 * @gw
|
|
colour = Meteor.call("strokeAndThickness",colour, false)
|
|
|
|
@obj = @paper.text(x/100, y/100, "")
|
|
@obj.attr
|
|
fill: Meteor.call("strokeAndThickness",colour, false)
|
|
"font-family": "Arial" # TODO: make dynamic
|
|
"font-size": calcFontSize
|
|
@obj.node.style["text-anchor"] = "start" # force left align
|
|
@obj.node.style["textAnchor"] = "start" # for firefox, 'cause they like to be different
|
|
@obj
|
|
|
|
# Update text shape drawn
|
|
# @param {object} the object containing the shape info
|
|
update: (startingData) ->
|
|
#console.log "updating text" + JSON.stringify startingData
|
|
|
|
x = startingData.x
|
|
y = startingData.y
|
|
maxWidth = startingData.textBoxWidth
|
|
height = startingData.textBoxHeight
|
|
colour = startingData.fontColor
|
|
fontSize = startingData.fontSize
|
|
calcFontSize = startingData.calcedFontSize
|
|
myText = startingData.text
|
|
|
|
if @obj?
|
|
@definition.data = [x, y, maxWidth, height, colour, fontSize, calcFontSize, myText]
|
|
|
|
calcFontSize = (calcFontSize/100 * @gh)
|
|
x = (x * @gw)/100 + @xOffset
|
|
maxWidth = maxWidth/100 * @gw
|
|
|
|
@obj.attr
|
|
fill: "#000"
|
|
"font-size": calcFontSize
|
|
cell = @obj.node
|
|
while cell? and cell.hasChildNodes()
|
|
cell.removeChild(cell.firstChild)
|
|
|
|
# used code from textFlow lib http://www.carto.net/papers/svg/textFlow/
|
|
# but had to merge it here because "cell" was bigger than what the stack could take
|
|
|
|
#extract and add line breaks for start
|
|
dashArray = new Array()
|
|
dashFound = true
|
|
indexPos = 0
|
|
cumulY = 0
|
|
svgNS = "http://www.w3.org/2000/svg"
|
|
while dashFound is true
|
|
result = myText.indexOf("-", indexPos)
|
|
if result is -1
|
|
#could not find a dash
|
|
dashFound = false
|
|
else
|
|
dashArray.push result
|
|
indexPos = result + 1
|
|
#split the text at all spaces and dashes
|
|
words = myText.split(/[\s-]/)
|
|
line = ""
|
|
dy = 0
|
|
curNumChars = 0
|
|
computedTextLength = 0
|
|
myTextNode = undefined
|
|
tspanEl = undefined
|
|
i = 0
|
|
while i < words.length
|
|
word = words[i]
|
|
curNumChars += word.length + 1
|
|
if computedTextLength > maxWidth or i is 0
|
|
if computedTextLength > maxWidth
|
|
tempText = tspanEl.firstChild.nodeValue
|
|
tempText = tempText.slice(0, (tempText.length - words[i - 1].length - 2)) #the -2 is because we also strip off white space
|
|
tspanEl.firstChild.nodeValue = tempText
|
|
|
|
#alternatively one could use textLength and lengthAdjust, however, currently this is not too well supported in SVG UA's
|
|
tspanEl = document.createElementNS(svgNS, "tspan")
|
|
tspanEl.setAttributeNS null, "x", x
|
|
tspanEl.setAttributeNS null, "dy", dy
|
|
myTextNode = document.createTextNode(line)
|
|
tspanEl.appendChild myTextNode
|
|
cell.appendChild tspanEl
|
|
if checkDashPosition(dashArray, curNumChars - 1)
|
|
line = word + "-"
|
|
else
|
|
line = word + " "
|
|
line = words[i - 1] + " " + line unless i is 0
|
|
dy = calcFontSize
|
|
cumulY += dy
|
|
else
|
|
if checkDashPosition(dashArray, curNumChars - 1)
|
|
line += word + "-"
|
|
else
|
|
line += word + " "
|
|
tspanEl.firstChild.nodeValue = line
|
|
computedTextLength = tspanEl.getComputedTextLength()
|
|
if i is words.length - 1
|
|
if computedTextLength > maxWidth
|
|
tempText = tspanEl.firstChild.nodeValue
|
|
tspanEl.firstChild.nodeValue = tempText.slice(0, (tempText.length - words[i].length - 1))
|
|
tspanEl = document.createElementNS(svgNS, "tspan")
|
|
tspanEl.setAttributeNS null, "x", x
|
|
tspanEl.setAttributeNS null, "dy", dy
|
|
myTextNode = document.createTextNode(words[i])
|
|
tspanEl.appendChild myTextNode
|
|
cell.appendChild tspanEl
|
|
i++
|
|
cumulY
|
|
|
|
|
|
#this function checks if there should be a dash at the given position, instead of a blank
|
|
checkDashPosition = (dashArray, pos) ->
|
|
result = false
|
|
i = 0
|
|
while i < dashArray.length
|
|
result = true if dashArray[i] is pos
|
|
i++
|
|
result
|
|
|
|
|
|
# Draw a text on the whiteboard
|
|
# @param {string} colour the colour of the object
|
|
# @param {number} thickness the thickness of the object's line(s)
|
|
# draw: (x, y, width, height, colour, fontSize, calcFontSize, text) ->
|
|
# calcFontSize = (calcFontSize/100 * @gh)
|
|
# x = x * @gw + @xOffset
|
|
# y = (y * @gh) + @yOffset + calcFontSize
|
|
# width = width/100 * @gw
|
|
# #colour = Utils.strokeAndThickness(colour)["stroke"]
|
|
|
|
|
|
# el = @paper.text(x, y, "")
|
|
# el.attr
|
|
# fill: Meteor.call("strokeAndThickness",colour, false)
|
|
# "font-family": "Arial" # TODO: make dynamic
|
|
# "font-size": calcFontSize
|
|
# el.node.style["text-anchor"] = "start" # force left align
|
|
# el.node.style["textAnchor"] = "start" # for firefox, 'cause they like to be different
|
|
# Meteor.call("textFlow", text, el.node, width, x, calcFontSize, false)
|
|
# el
|
|
|
|
# When first dragging the mouse to create the textbox size
|
|
# @param {number} x the x value of cursor at the time in relation to the left side of the browser
|
|
# @param {number} y the y value of cursor at the time in relation to the top of the browser
|
|
# TODO: moved here but not finished nor tested
|
|
# _textStart: (x, y) ->
|
|
# [sw, sh] = @_currentSlideDimensions()
|
|
# [cx, cy] = @_currentSlideOffsets()
|
|
# if @currentText?
|
|
# globals.connection.emitPublishShape "text",
|
|
# [ @textbox.value, @currentText.attrs.x / @gw, @currentText.attrs.y / @gh,
|
|
# @textbox.clientWidth, 16, @currentColour, "Arial", 14 ]
|
|
# globals.connection.emitTextDone()
|
|
# @textbox.value = ""
|
|
# @textbox.style.visibility = "hidden"
|
|
# @textX = x
|
|
# @textY = y
|
|
# sx = (@containerWidth - @gw) / 2
|
|
# sy = (@containerHeight - @gh) / 2
|
|
# @cx2 = (x - @containerOffsetLeft - sx + cx) / sw
|
|
# @cy2 = (y - @containerOffsetTop - sy + cy) / sh
|
|
# @_makeRect @cx2, @cy2, "#000", 1
|
|
# globals.connection.emitMakeShape "rect", [ @cx2, @cy2, "#000", 1 ]
|
|
|
|
# Finished drawing the rectangle that the text will fit into
|
|
# @param {Event} e the mouse event
|
|
# TODO: moved here but not finished nor tested
|
|
# _textStop: (e) ->
|
|
# @currentRect.hide() if @currentRect?
|
|
# [sw, sh] = @_currentSlideDimensions()
|
|
# [cx, cy] = @_currentSlideOffsets()
|
|
# tboxw = (e.pageX - @textX)
|
|
# tboxh = (e.pageY - @textY)
|
|
# if tboxw >= 14 or tboxh >= 14 # restrict size
|
|
# @textbox.style.width = tboxw * (@gw / sw) + "px"
|
|
# @textbox.style.visibility = "visible"
|
|
# @textbox.style["font-size"] = 14 + "px"
|
|
# @textbox.style["fontSize"] = 14 + "px" # firefox
|
|
# @textbox.style.color = @currentColour
|
|
# @textbox.value = ""
|
|
# sx = (@containerWidth - @gw) / 2
|
|
# sy = (@containerHeight - @gh) / 2
|
|
# x = @textX - @containerOffsetLeft - sx + cx + 1 # 1px random padding
|
|
# y = @textY - @containerOffsetTop - sy + cy
|
|
# @textbox.focus()
|
|
|
|
# # if you click outside, it will automatically sumbit
|
|
# @textbox.onblur = (e) =>
|
|
# if @currentText
|
|
# globals.connection.emitPublishShape "text",
|
|
# [ @value, @currentText.attrs.x / @gw, @currentText.attrs.y / @gh,
|
|
# @textbox.clientWidth, 16, @currentColour, "Arial", 14 ]
|
|
# globals.connection.emitTextDone()
|
|
# @textbox.value = ""
|
|
# @textbox.style.visibility = "hidden"
|
|
|
|
# # if user presses enter key, then automatically submit
|
|
# @textbox.onkeypress = (e) ->
|
|
# if e.keyCode is "13"
|
|
# e.preventDefault()
|
|
# e.stopPropagation()
|
|
# @onblur()
|
|
|
|
# # update everyone with the new text at every change
|
|
# _paper = @
|
|
# @textbox.onkeyup = (e) ->
|
|
# @style.color = _paper.currentColour
|
|
# @value = @value.replace(/\n{1,}/g, " ").replace(/\s{2,}/g, " ")
|
|
# globals.connection.emitUpdateShape "text",
|
|
# [ @value, x / _paper.sw, (y + (14 * (_paper.sh / _paper.gh))) / _paper.sh,
|
|
# tboxw * (_paper.gw / _paper.sw), 16, _paper.currentColour, "Arial", 14 ]
|
|
|
|
# The server has said the text is finished,
|
|
# so set it to null for the next text object
|
|
# TODO: moved here but not finished nor tested
|
|
# textDone: ->
|
|
# if @currentText?
|
|
# @currentText = null
|
|
# @currentRect.hide() if @currentRect?
|