Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
X
xblock-vectordraw
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
xblock-vectordraw
Commits
06eacfc7
Commit
06eacfc7
authored
Nov 04, 2015
by
Tim Krones
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Address review comments.
parent
fbc4ea48
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
103 additions
and
113 deletions
+103
-113
vectordraw/public/css/vectordraw.css
+12
-14
vectordraw/public/js/vectordraw.js
+3
-73
vectordraw/templates/html/vectordraw.html
+0
-0
vectordraw/vectordraw.py
+88
-26
No files found.
vectordraw/
stat
ic/css/vectordraw.css
→
vectordraw/
publ
ic/css/vectordraw.css
View file @
06eacfc7
...
@@ -27,6 +27,7 @@
...
@@ -27,6 +27,7 @@
}
}
.vectordraw_block
.menu
.controls
{
.vectordraw_block
.menu
.controls
{
display
:
table
;
margin-bottom
:
20px
;
margin-bottom
:
20px
;
font-size
:
0
;
font-size
:
0
;
}
}
...
@@ -39,7 +40,7 @@
...
@@ -39,7 +40,7 @@
.vectordraw_block
.menu
.controls
button
{
.vectordraw_block
.menu
.controls
button
{
display
:
inline-block
;
display
:
inline-block
;
background-color
:
#
3498db
;
background-color
:
#
c2e0f4
;
border-radius
:
5px
;
border-radius
:
5px
;
box-shadow
:
0
1px
3px
#666
;
box-shadow
:
0
1px
3px
#666
;
color
:
#1f628d
;
color
:
#1f628d
;
...
@@ -52,22 +53,19 @@
...
@@ -52,22 +53,19 @@
}
}
.vectordraw_block
.menu
.controls
button
:hover
{
.vectordraw_block
.menu
.controls
button
:hover
{
background
:
#
3cb0fd
;
background
:
#
c2e0f4
;
background-image
:
-webkit-linear-gradient
(
top
,
#
3cb0fd
,
#3498db
);
background-image
:
-webkit-linear-gradient
(
top
,
#
c2e0f4
,
#add5f0
);
background-image
:
-moz-linear-gradient
(
top
,
#
3cb0fd
,
#3498db
);
background-image
:
-moz-linear-gradient
(
top
,
#
c2e0f4
,
#add5f0
);
background-image
:
-ms-linear-gradient
(
top
,
#
3cb0fd
,
#3498db
);
background-image
:
-ms-linear-gradient
(
top
,
#
c2e0f4
,
#add5f0
);
background-image
:
-o-linear-gradient
(
top
,
#
3cb0fd
,
#3498db
);
background-image
:
-o-linear-gradient
(
top
,
#
c2e0f4
,
#add5f0
);
background-image
:
linear-gradient
(
to
bottom
,
#
3cb0fd
,
#3498db
);
background-image
:
linear-gradient
(
to
bottom
,
#
c2e0f4
,
#add5f0
);
text-decoration
:
none
;
text-decoration
:
none
;
}
}
vectordraw_block
.menu
.controls
button
.undo
,
.vectordraw_block
.menu
.controls
button
.undo
,
vectordraw_block
.menu
.controls
button
.redo
{
.vectordraw_block
.menu
.controls
button
.redo
{
width
:
78px
;
display
:
table-cell
;
}
width
:
50%
;
.vectordraw_block
.menu
.controls
button
.undo
{
margin-right
:
4px
;
}
}
.vectordraw_block
.menu
.vector-properties
{
.vectordraw_block
.menu
.vector-properties
{
...
...
vectordraw/
static/js/src
/vectordraw.js
→
vectordraw/
public/js
/vectordraw.js
View file @
06eacfc7
...
@@ -9,7 +9,7 @@ function VectorDrawXBlock(runtime, element, init_args) {
...
@@ -9,7 +9,7 @@ function VectorDrawXBlock(runtime, element, init_args) {
this
.
dragged_vector
=
null
;
this
.
dragged_vector
=
null
;
this
.
drawMode
=
false
;
this
.
drawMode
=
false
;
this
.
history_stack
=
{
undo
:
[],
redo
:
[]};
this
.
history_stack
=
{
undo
:
[],
redo
:
[]};
this
.
settings
=
this
.
sanitizeSettings
(
settings
)
;
this
.
settings
=
settings
;
this
.
element
=
$
(
'#'
+
element_id
);
this
.
element
=
$
(
'#'
+
element_id
);
this
.
element
.
on
(
'click'
,
'.reset'
,
this
.
reset
.
bind
(
this
));
this
.
element
.
on
(
'click'
,
'.reset'
,
this
.
reset
.
bind
(
this
));
...
@@ -22,76 +22,6 @@ function VectorDrawXBlock(runtime, element, init_args) {
...
@@ -22,76 +22,6 @@ function VectorDrawXBlock(runtime, element, init_args) {
this
.
render
();
this
.
render
();
};
};
VectorDraw
.
prototype
.
sanitizeSettings
=
function
(
settings
)
{
// Fill in defaults at top level of settings.
var
default_settings
=
{
width
:
550
,
height
:
400
,
axis
:
false
,
background
:
null
,
bounding_box_size
:
10
,
show_navigation
:
false
,
show_vector_properties
:
true
,
add_vector_label
:
'Add Selected Force'
,
vector_properties_label
:
'Vector Properties'
,
vectors
:
[],
points
:
[],
expected_result
:
{},
custom_checks
:
[],
unit_vector_ratio
:
1
};
_
.
defaults
(
settings
,
default_settings
);
var
width_scale
=
settings
.
width
/
settings
.
height
,
box_size
=
settings
.
bounding_box_size
;
settings
.
bounding_box
=
[
-
box_size
*
width_scale
,
box_size
,
box_size
*
width_scale
,
-
box_size
];
// Fill in defaults for vectors.
var
default_vector
=
{
type
:
'vector'
,
render
:
false
,
length_factor
:
1
,
length_units
:
''
,
base_angle
:
0
,
style
:
{}
};
var
default_vector_style
=
{
pointSize
:
1
,
pointColor
:
'red'
,
width
:
4
,
color
:
"blue"
,
label
:
null
,
labelColor
:
'black'
};
settings
.
vectors
.
forEach
(
function
(
vector
)
{
_
.
defaults
(
vector
,
default_vector
);
_
.
defaults
(
vector
.
style
,
default_vector_style
);
});
// Fill in defaults for points.
var
default_point
=
{
fixed
:
true
,
// Default to true for backwards compatibility.
render
:
true
,
style
:
{}
};
var
default_point_style
=
{
size
:
1
,
withLabel
:
false
,
color
:
'pink'
,
showInfoBox
:
false
};
settings
.
points
.
forEach
(
function
(
point
)
{
_
.
defaults
(
point
,
default_point
);
_
.
defaults
(
point
.
style
,
default_point_style
);
point
.
style
.
name
=
point
.
name
;
point
.
style
.
fixed
=
point
.
fixed
;
point
.
style
.
strokeColor
=
point
.
style
.
color
;
point
.
style
.
fillColor
=
point
.
style
.
color
;
delete
point
.
style
.
color
;
});
return
settings
;
};
VectorDraw
.
prototype
.
render
=
function
()
{
VectorDraw
.
prototype
.
render
=
function
()
{
// Assign the jxgboard element a random unique ID,
// Assign the jxgboard element a random unique ID,
// because JXG.JSXGraph.initBoard needs it.
// because JXG.JSXGraph.initBoard needs it.
...
@@ -112,7 +42,7 @@ function VectorDrawXBlock(runtime, element, init_args) {
...
@@ -112,7 +42,7 @@ function VectorDrawXBlock(runtime, element, init_args) {
});
});
function
getImageRatio
(
bg
,
callback
)
{
function
getImageRatio
(
bg
,
callback
)
{
$
(
'<img/>'
).
attr
(
'src'
,
bg
.
src
).
load
(
function
(){
$
(
'<img/>'
).
attr
(
'src'
,
bg
.
src
).
load
(
function
()
{
//technically it's inverse of ratio, but we need it to calculate height
//technically it's inverse of ratio, but we need it to calculate height
var
ratio
=
this
.
height
/
this
.
width
;
var
ratio
=
this
.
height
/
this
.
width
;
callback
(
bg
,
ratio
);
callback
(
bg
,
ratio
);
...
@@ -562,7 +492,7 @@ function VectorDrawXBlock(runtime, element, init_args) {
...
@@ -562,7 +492,7 @@ function VectorDrawXBlock(runtime, element, init_args) {
});
});
});
});
input
.
checks
=
checks
.
concat
(
vectordraw
.
settings
.
custom_checks
)
;
input
.
checks
=
checks
;
return
input
;
return
input
;
}
}
...
...
vectordraw/
static
/html/vectordraw.html
→
vectordraw/
templates
/html/vectordraw.html
View file @
06eacfc7
File moved
vectordraw/vectordraw.py
View file @
06eacfc7
...
@@ -228,10 +228,13 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
...
@@ -228,10 +228,13 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
"""
"""
Return settings for this exercise.
Return settings for this exercise.
"""
"""
width_scale
=
self
.
width
/
float
(
self
.
height
)
box_size
=
self
.
bounding_box_size
bounding_box
=
[
-
box_size
*
width_scale
,
box_size
,
box_size
*
width_scale
,
-
box_size
]
return
{
return
{
'width'
:
self
.
width
,
'width'
:
self
.
width
,
'height'
:
self
.
height
,
'height'
:
self
.
height
,
'bounding_box
_size'
:
self
.
bounding_box_size
,
'bounding_box
'
:
bounding_box
,
'axis'
:
self
.
axis
,
'axis'
:
self
.
axis
,
'show_navigation'
:
self
.
show_navigation
,
'show_navigation'
:
self
.
show_navigation
,
'show_vector_properties'
:
self
.
show_vector_properties
,
'show_vector_properties'
:
self
.
show_vector_properties
,
...
@@ -241,7 +244,7 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
...
@@ -241,7 +244,7 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
'background'
:
self
.
background
,
'background'
:
self
.
background
,
'vectors'
:
self
.
get_vectors
,
'vectors'
:
self
.
get_vectors
,
'points'
:
self
.
get_points
,
'points'
:
self
.
get_points
,
'expected_result'
:
self
.
get_expected_result
'expected_result'
:
self
.
get_expected_result
,
}
}
@property
@property
...
@@ -265,26 +268,83 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
...
@@ -265,26 +268,83 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
'height'
:
self
.
background_height
,
'height'
:
self
.
background_height
,
}
}
def
_get_default_vector
(
self
):
# pylint: disable=no-self-use
"""
Return dictionary that represents vector with default values filled in.
"""
return
{
'type'
:
'vector'
,
'render'
:
False
,
'length_factor'
:
1
,
'length_units'
:
''
,
'base_angle'
:
0
,
'style'
:
{
'pointSize'
:
1
,
'pointColor'
:
'red'
,
'width'
:
4
,
'color'
:
'blue'
,
'label'
:
None
,
'labelColor'
:
'black'
}
}
@property
@property
def
get_vectors
(
self
):
def
get_vectors
(
self
):
"""
"""
Load info about vectors for this exercise from JSON string specified by course author.
Return info about vectors belonging to this exercise.
To do this, load vector info from JSON string specified by course author,
and augment it with default values that are required for rendering vectors on the client.
"""
vectors
=
[]
for
vector
in
json
.
loads
(
self
.
vectors
):
default_vector
=
self
.
_get_default_vector
()
default_vector_style
=
default_vector
[
'style'
]
if
'style'
in
vector
:
default_vector_style
.
update
(
vector
[
'style'
])
del
vector
[
'style'
]
default_vector
.
update
(
vector
)
vectors
.
append
(
default_vector
)
return
vectors
def
_get_default_point
(
self
):
# pylint: disable=no-self-use
"""
"""
return
json
.
loads
(
self
.
vectors
)
Return dictionary that represents point with default values filled in.
"""
return
{
'fixed'
:
True
,
# Default to True for backwards compatibility
'render'
:
True
,
'style'
:
{
'size'
:
1
,
'withLabel'
:
False
,
'color'
:
'pink'
,
'showInfoBox'
:
False
}
}
@property
@property
def
get_points
(
self
):
def
get_points
(
self
):
"""
"""
Load info about points for this exercise from JSON string specified by course author.
Return info about points belonging to this exercise.
To do this, load point info from JSON string specified by course author,
and augment it with default values that are required for rendering points on the client.
"""
"""
points
=
json
.
loads
(
self
.
points
)
points
=
[]
for
point
in
points
:
for
point
in
json
.
loads
(
self
.
points
):
# If author did not specify whether point should be drawn in fixed location (True)
default_point
=
self
.
_get_default_point
()
# or placed by student (False), we default to True;
default_point_style
=
default_point
[
'style'
]
# template needs this info to determine whether it should add option
if
'style'
in
point
:
# for selecting point to dropdown menu:
default_point_style
.
update
(
point
[
'style'
])
if
'fixed'
not
in
point
:
del
point
[
'style'
]
point
[
'fixed'
]
=
True
default_point
.
update
(
point
)
default_point_style
[
'name'
]
=
default_point
[
'name'
]
default_point_style
[
'fixed'
]
=
default_point
[
'fixed'
]
point_color
=
default_point_style
[
'color'
]
default_point_style
[
'strokeColor'
]
=
point_color
default_point_style
[
'fillColor'
]
=
point_color
del
default_point_style
[
'color'
]
points
.
append
(
default_point
)
return
points
return
points
@property
@property
...
@@ -300,13 +360,14 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
...
@@ -300,13 +360,14 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
The primary view of the VectorDrawXBlock, shown to students
The primary view of the VectorDrawXBlock, shown to students
when viewing courses.
when viewing courses.
"""
"""
context
=
context
or
{}
context
[
'self'
]
=
self
context
[
'self'
]
=
self
fragment
=
Fragment
()
fragment
=
Fragment
()
fragment
.
add_content
(
loader
.
render_template
(
'
static
/html/vectordraw.html'
,
context
))
fragment
.
add_content
(
loader
.
render_template
(
'
templates
/html/vectordraw.html'
,
context
))
fragment
.
add_css_url
(
fragment
.
add_css_url
(
"//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/css/font-awesome.min.css"
"//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/css/font-awesome.min.css"
)
)
fragment
.
add_css
(
loader
.
load_unicode
(
'stat
ic/css/vectordraw.css'
))
fragment
.
add_css
_url
(
self
.
runtime
.
local_resource_url
(
self
,
'publ
ic/css/vectordraw.css'
))
# Workbench doesn't have Underscore.js, so add it:
# Workbench doesn't have Underscore.js, so add it:
if
WorkbenchRuntime
and
isinstance
(
self
.
runtime
,
WorkbenchRuntime
):
if
WorkbenchRuntime
and
isinstance
(
self
.
runtime
,
WorkbenchRuntime
):
fragment
.
add_javascript_url
(
fragment
.
add_javascript_url
(
...
@@ -315,41 +376,42 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
...
@@ -315,41 +376,42 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
fragment
.
add_javascript_url
(
fragment
.
add_javascript_url
(
"//cdnjs.cloudflare.com/ajax/libs/jsxgraph/0.98/jsxgraphcore.js"
"//cdnjs.cloudflare.com/ajax/libs/jsxgraph/0.98/jsxgraphcore.js"
)
)
fragment
.
add_javascript
(
loader
.
load_unicode
(
"static/js/src/vectordraw.js"
))
fragment
.
add_javascript_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/js/vectordraw.js'
)
)
fragment
.
initialize_js
(
fragment
.
initialize_js
(
'VectorDrawXBlock'
,
{
"settings"
:
self
.
settings
,
"user_state"
:
self
.
user_state
}
'VectorDrawXBlock'
,
{
"settings"
:
self
.
settings
,
"user_state"
:
self
.
user_state
}
)
)
return
fragment
return
fragment
def
is_valid
(
self
,
data
):
# pylint: disable=no-self-use
def
_validate_check_answer_data
(
self
,
data
):
# pylint: disable=no-self-use
"""
"""
Validate answer data submitted by user.
Validate answer data submitted by user.
"""
"""
# Check vectors
# Check vectors
vectors
=
data
.
get
(
'vectors'
)
vectors
=
data
.
get
(
'vectors'
)
if
vectors
is
None
:
if
not
isinstance
(
vectors
,
dict
)
:
return
False
return
False
for
vector_data
in
vectors
.
values
():
for
vector_data
in
vectors
.
values
():
# Validate vector
# Validate vector
vector_valid
=
'tip'
in
vector_data
and
'tail'
in
vector_data
if
not
vector_data
.
viewkeys
()
==
{
'tail'
,
'tip'
}:
if
not
vector_valid
:
return
False
return
False
# Validate tip and tail
# Validate tip and tail
tip
=
vector_data
[
'tip'
]
tip
=
vector_data
[
'tip'
]
tip_valid
=
type
(
tip
)
==
list
and
len
(
tip
)
==
2
tip_valid
=
isinstance
(
tip
,
list
)
and
len
(
tip
)
==
2
tail
=
vector_data
[
'tail'
]
tail
=
vector_data
[
'tail'
]
tail_valid
=
type
(
tail
)
==
list
and
len
(
tail
)
==
2
tail_valid
=
isinstance
(
tail
,
list
)
and
len
(
tail
)
==
2
if
not
(
tip_valid
and
tail_valid
):
if
not
(
tip_valid
and
tail_valid
):
return
False
return
False
# Check points
# Check points
points
=
data
.
get
(
'points'
)
points
=
data
.
get
(
'points'
)
if
points
is
None
:
if
not
isinstance
(
points
,
dict
)
:
return
False
return
False
for
coords
in
points
.
values
():
for
coords
in
points
.
values
():
# Validate point
# Validate point
point_valid
=
type
(
coords
)
==
list
and
len
(
coords
)
==
2
point_valid
=
isinstance
(
coords
,
list
)
and
len
(
coords
)
==
2
if
not
point_valid
:
if
not
point_valid
:
break
return
False
# If we get to this point, it means that vector and point data is valid;
# If we get to this point, it means that vector and point data is valid;
# the only thing left to check is whether data contains a list of checks:
# the only thing left to check is whether data contains a list of checks:
return
'checks'
in
data
return
'checks'
in
data
...
@@ -360,7 +422,7 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
...
@@ -360,7 +422,7 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
Check and persist student's answer to this vector drawing problem.
Check and persist student's answer to this vector drawing problem.
"""
"""
# Validate data
# Validate data
if
not
self
.
is_valid
(
data
):
if
not
self
.
_validate_check_answer_data
(
data
):
raise
JsonHandlerError
(
400
,
"Invalid data"
)
raise
JsonHandlerError
(
400
,
"Invalid data"
)
# Save answer
# Save answer
self
.
answer
=
dict
(
self
.
answer
=
dict
(
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment