Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Background image, highlighter tool #139

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions client/lib/dom.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export svgTags =
circle: true
ellipse: true
text: true
image: true

export create = (tag, attrs, props, events, children) ->
if tag of svgTags
Expand Down
4 changes: 4 additions & 0 deletions client/lib/icons.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ export icons =
'<path d="M398.2,329.1H292.1l55.8,136c3.9,9.4-0.6,20-9.4,24l-49.2,21.4c-9.2,4-19.4-0.6-23.3-9.7l-53.1-129.1l-86.7,89.1C114.7,472.7,96,463.6,96,448V18.3c0-16.4,19.9-24.4,30.3-12.9L410.7,298C422.2,309.2,413.7,329.1,398.2,329.1L398.2,329.1z"/>'
'pencil-alt':
'<path d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"/>'
'highlighter':
'<path d="M0 479.98L99.92 512l35.45-35.45-67.04-67.04L0 479.98zm124.61-240.01a36.592 36.592 0 0 0-10.79 38.1l13.05 42.83-50.93 50.94 96.23 96.23 50.86-50.86 42.74 13.08c13.73 4.2 28.65-.01 38.15-10.78l35.55-41.64-173.34-173.34-41.52 35.44zm403.31-160.7l-63.2-63.2c-20.49-20.49-53.38-21.52-75.12-2.35L190.55 183.68l169.77 169.78L530.27 154.4c19.18-21.74 18.15-54.63-2.35-75.13z"/>'
plus:
'<path d="M448,208H304V64c0-17.7-14.3-32-32-32h-32c-17.7,0-32,14.3-32,32v144H64c-17.7,0-32,14.3-32,32v32c0,17.7,14.3,32,32,32h144v144c0,17.7,14.3,32,32,32h32c17.7,0,32-14.3,32-32V304h144c17.7,0,32-14.3,32-32v-32C480,222.3,465.7,208,448,208z"/>'
'plus-square':
Expand Down Expand Up @@ -75,6 +77,8 @@ export icons =
'<path d="M256,468c-67.1,0-130.5-21.2-178.4-59.8c-24-19.3-42.9-41.9-56.3-67.3C7.2,314.1,0,285.5,0,256s7.2-58.1,21.3-85c13.3-25.3,32.3-48,56.3-67.3C125.5,65.2,188.9,44,256,44c67.1,0,130.5,21.2,178.4,59.8c24,19.3,42.9,41.9,56.3,67.3c14.1,26.8,21.3,55.4,21.3,85s-7.2,58.1-21.3,85c-13.3,25.3-32.3,48-56.3,67.3C386.5,446.8,323.1,468,256,468zM256,108c-52.6,0-101.7,16.2-138.3,45.7C83.1,181.5,64,217.8,64,256s19.1,74.5,53.7,102.3C154.3,387.8,203.4,404,256,404c52.6,0,101.7-16.2,138.3-45.7C428.9,330.5,448,294.2,448,256s-19.1-74.5-53.7-102.3C357.7,124.2,308.6,108,256,108z"/>'
'ellipse-fill': # center of above
'<path d="M256,404c-106,0-192-66.3-192-148s86-148,192-148s192,66.3,192,148S362,404,256,404z"/>'
background:
'<path d="M464 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48zM112 120c-30.928 0-56 25.072-56 56s25.072 56 56 56 56-25.072 56-56-25.072-56-56-56zM64 384h384V272l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L208 320l-55.515-55.515c-4.686-4.686-12.284-4.686-16.971 0L64 336v48z"/>'
grid: # edited border-all to extend (more) beyond square
'<rect x="52" width="64" height="512"/><rect x="224" width="64" height="512"/><rect x="396" width="64" height="512"/><rect y="52" width="512" height="64"/><rect y="224" width="512" height="64"/><rect y="396" width="512" height="64"/>'
'grid-snap': # based on grid above and vector-square
Expand Down
82 changes: 73 additions & 9 deletions client/main.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {meteorCallPromise} from '/lib/meteorPromise'

board = historyBoard = null # Board objects
gridDefault = true
bgDefault = false
selection = null # Selection object representing selected objects
undoStack = []
redoStack = []
Expand All @@ -18,8 +19,12 @@ dragDist = 2 # require movement by this many pixels before select drags
remoteIconSize = 24
remoteIconOutside = 0.2 # fraction to render icons outside view
export room = null
currentFill = 'white'
currentFill = '#ffffff'
currentFillOn = false
hilite = ''
hiliteWidth = 1
currentColor = '#000000'
currentWidth = 5
name = new storage.StringVariable 'name', '', updateName = ->
nameInput = document.getElementById 'name'
nameInput.value = name.get() unless nameInput.value == name.get()
Expand Down Expand Up @@ -569,6 +574,11 @@ tools =
once: ->
dark.set not dark.get()
updateDark()
background:
icon: 'background'
help: 'Toggle background image'
once: ->
Meteor.call 'bgToggle', room.page
grid:
icon: 'grid'
help: 'Toggle grid/graph paper'
Expand Down Expand Up @@ -760,6 +770,11 @@ tools =
Boolean room.pageData.grid
else
gridDefault
bg:
if room.pageData?
Boolean room.pageData.bg
else
bgDefault
, index+1
, (error, page) ->
if error?
Expand Down Expand Up @@ -824,7 +839,26 @@ tools =
selection.edit 'fill', if currentFillOn then currentFill else null
else
selectDrawingTool()

hiliter:
palette: 'colors'
icon: 'highlighter'
help: 'Turn current tool into highlight (wider and translucent)'
hotkey: 'h'
once: ->
if not hilite
hilite = '20'
hiliteWidth = 4
currentColor += hilite
currentFill += hilite
currentWidth *= hiliteWidth
else
currentColor = currentColor?.slice(0, -hilite.length)
currentFill = currentColor?.slice(0, -hilite.length)
currentWidth = currentWidth / hiliteWidth
hilite = ''
hiliteWidth = 1
tool = document.querySelector('.tool[data-tool="hiliter"]')
dom.classSet tool, 'active', hilite
currentTool = 'pan'
drawingTools =
pen: true
Expand All @@ -842,11 +876,11 @@ currentBoard = ->
board

colors = [
'black' # Windows Journal black
'#000000' # Windows Journal black
'#666666' # Windows Journal grey
'#989898' # medium grey
'#bbbbbb' # lighter grey
'white'
'#ffffff'
'#333399' # Windows Journal dark blue
'#3366ff' # Windows Journal light blue
'#00c7c7' # custom light cyan
Expand All @@ -861,7 +895,7 @@ colors = [
'#ed8e00' # custom orange
'#eced00' # custom yellow
]
currentColor = 'black'
currentColor = '#000000'

widths = [
1
Expand Down Expand Up @@ -1226,7 +1260,7 @@ class Selection
if (color = uniformAttribute 'color')? # uniform draw color
selectColor color, true, true
if (fill = uniformAttribute 'fill', false)? # uniform actual fill color
currentFill = fill
currentFill = fill + hilite
currentFillOn = true
updateFill()
if fill == undefined # uniform no fill
Expand Down Expand Up @@ -1339,6 +1373,7 @@ class Board
@bbox = currentBoard().svg.getBoundingClientRect()
@remotesRender?.resize()
@grid?.update()
@bg?.update()
setScaleFixingPoint: (newScale, fixed) ->
###
Transform point (x,y) while preserving (fixed.x, fixed.y):
Expand Down Expand Up @@ -1387,6 +1422,9 @@ class Board
Meteor.setTimeout =>
@grid?.update()
, 0
Meteor.setTimeout =>
@bg?.update()
, 0
renderedChildren: ->
for child in @root.childNodes
skip = false
Expand Down Expand Up @@ -1819,6 +1857,7 @@ render = null
observeRender = ->
board.clear()
render = new Render board.root
board.bg = new Background board.root
board.grid = new Grid board.root
Objects.find
room: room.id
Expand Down Expand Up @@ -2001,6 +2040,25 @@ class Grid
x2: bounds.max.x + margin
#else

class Background
constructor: (root) ->
dom.classSet document.querySelector('.tool[data-tool="background"]'),
'present', room.data?.bgimg
@svg = root.parentNode
root.appendChild @bg = dom.create 'g',
class: 'bg'
@update()
update: (mode = room?.pageBg, bounds) ->
@bg.innerHTML = ''
bounds ?=
min: dom.svgPoint @svg, board.bbox.left, board.bbox.top, @grid
max: dom.svgPoint @svg, board.bbox.right, board.bbox.bottom, @grid
switch mode
when true
@bg.appendChild dom.create 'image',
href: room.data.bgimg
#else

loadingCount = 0
loadingUpdate = (delta) ->
loadingCount += delta
Expand Down Expand Up @@ -2079,6 +2137,11 @@ class Room
dom.classSet document.querySelector('.tool[data-tool="grid"]'),
'active', @pageGrid
board.grid?.update()
if @pageBg != @pageData?.bg
@pageBg = @pageData?.bg
dom.classSet document.querySelector('.tool[data-tool="background"]'),
'active', @pageBg
board.bg?.update()
updatePageNum: ->
pageNumber = @pageIndex()
pageNumber++ if pageNumber?
Expand All @@ -2103,6 +2166,7 @@ urlChange = ->
if document.location.pathname == '/'
Meteor.call 'roomNew',
grid: gridDefault
bg: bgDefault
, (error, data) ->
if error?
updateBadRoom() # should display visible error message
Expand Down Expand Up @@ -2324,7 +2388,7 @@ drawingToolIcon = (tool, color, fill) ->
icon

selectColor = (color, keepTool, skipSelection) ->
currentColor = color if color?
currentColor = (color + hilite) if color?
dom.select '.color', "[data-color='#{currentColor}']"
document.documentElement.style.setProperty '--currentColor', currentColor
if not skipSelection and selection.nonempty()
Expand All @@ -2334,7 +2398,7 @@ selectColor = (color, keepTool, skipSelection) ->
updateCursor()

selectFill = (color) ->
currentFill = color
currentFill = color + hilite
currentFillOn = true
updateFill()
if selection.nonempty()
Expand All @@ -2343,7 +2407,7 @@ selectFill = (color) ->
selectDrawingTool()

selectWidth = (width, keepTool, skipSelection) ->
currentWidth = parseFloat width if width?
currentWidth = (parseFloat width * hiliteWidth) if width?
if not skipSelection and selection.nonempty()
selection.edit 'width', currentWidth
keepTool = true
Expand Down
9 changes: 9 additions & 0 deletions client/main.styl
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,11 @@ input, textarea
margin-top: 1px
margin-left: 3px

.tool[data-tool="background"]
display: none
&.present
display: block

.tool[data-tool="fill"]
#fillOn
display: block
Expand Down Expand Up @@ -318,6 +323,10 @@ body.nopage
#download
display: none

.bg
pointer-events: none

.grid
pointer-events: none
stroke-width: 0.96
stroke: #c4e3f4
8 changes: 8 additions & 0 deletions lib/pages.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Meteor.methods
check page,
room: String
grid: Match.Optional Boolean
bg: Match.Optional Boolean
check index, Match.Optional Number
unless @isSimulation
now = new Date
Expand Down Expand Up @@ -54,3 +55,10 @@ Meteor.methods
Pages.update page,
$set: grid: not data.grid
, channel: "rooms::#{data.room}::pages"

bgToggle: (page) ->
check page, String
data = checkPage page
Pages.update page,
$set: bg: not data.bg
, channel: "rooms::#{data.room}::pages"
4 changes: 3 additions & 1 deletion lib/rooms.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ Meteor.methods
roomNew: (room = {}) ->
check room,
grid: Match.Optional Boolean
bg: Match.Optional Boolean
bgimg: Match.Optional String
## Move room-level data to initial page
page = {}
for key in ['grid'] when key of room
for key in ['grid', 'bg'] when key of room
page[key] = room[key]
delete room[key]
unless @isSimulation
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
},
"dependencies": {
"@babel/runtime": "^7.11.2",
"bcrypt": "^5.0.0",
"body-parser": "^1.19.0",
"markdownlint-rule-github-internal-links": "^0.0.1",
"meteor-node-stubs": "^1.0.1",
"pepjs": "^0.5.2",
Expand Down
18 changes: 13 additions & 5 deletions server/api.coffee
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import bodyParser from 'body-parser';

apiMethods =
'/roomNew': (options) ->
'/roomNew': (options, req) ->
try
ids = Meteor.call 'roomNew',
grid: Boolean JSON.parse options.get 'grid'
body = req.body
body.grid = Boolean JSON.parse body.grid or Boolean JSON.parse options.get 'grid'
body.bg = Boolean JSON.parse body.bg or Boolean JSON.parse options.get 'bg'
ids = Meteor.call 'roomNew', body
status: 200
json:
ok: true
Expand All @@ -15,12 +19,16 @@ apiMethods =
error: "Error creating new room: #{e}"

## Allow CORS for API calls
WebApp.connectHandlers.use '/api', (req, res, next) ->
WebApp.rawConnectHandlers.use '/api', (req, res, next) ->
res.setHeader 'Access-Control-Allow-Origin', '*'
res.setHeader 'Access-Control-Allow-Methods', '*'
res.setHeader 'Access-Control-Allow-Headers', '*'
next()

WebApp.connectHandlers.use '/api', bodyParser.json({limit: '16mb'})

WebApp.connectHandlers.use '/api', (req, res, next) ->
return unless req.method in ['GET', 'POST']
return unless req.method in ['GET', 'POST', 'OPTIONS']
url = new URL req.url, Meteor.absoluteUrl()
if apiMethods.hasOwnProperty url.pathname
result = apiMethods[url.pathname] url.searchParams, req, res, next
Expand Down