Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kazuhiko Shiozaki
gitlab-ce
Commits
4398bdf2
Commit
4398bdf2
authored
Dec 21, 2012
by
Dmitriy Zaporozhets
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'koenpunt-gh-issue-1509'
parents
a567d596
a47032bc
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
274 additions
and
199 deletions
+274
-199
app/assets/images/ajax_loader_gray.gif
app/assets/images/ajax_loader_gray.gif
+0
-0
app/assets/javascripts/projects.js.coffee
app/assets/javascripts/projects.js.coffee
+0
-7
app/assets/stylesheets/common.scss
app/assets/stylesheets/common.scss
+3
-0
app/controllers/projects_controller.rb
app/controllers/projects_controller.rb
+13
-9
app/views/projects/graph.html.haml
app/views/projects/graph.html.haml
+8
-6
lib/gitlab/graph/commit.rb
lib/gitlab/graph/commit.rb
+1
-1
lib/gitlab/graph/json_builder.rb
lib/gitlab/graph/json_builder.rb
+8
-9
vendor/assets/javascripts/branch-graph.js
vendor/assets/javascripts/branch-graph.js
+241
-167
No files found.
app/assets/images/ajax_loader_gray.gif
0 → 100644
View file @
4398bdf2
8.17 KB
app/assets/javascripts/projects.js.coffee
View file @
4398bdf2
...
...
@@ -18,10 +18,3 @@ $ ->
# Ref switcher
$
(
'.project-refs-select'
).
on
'change'
,
->
$
(
@
).
parents
(
'form'
).
submit
()
class
@
GraphNav
@
init
:
->
$
(
'.graph svg'
).
css
'position'
,
'relative'
$
(
'body'
).
bind
'keyup'
,
(
e
)
->
$
(
'.graph svg'
).
animate
(
left
:
'+=400'
)
if
e
.
keyCode
is
37
# left
$
(
'.graph svg'
).
animate
(
left
:
'-=400'
)
if
e
.
keyCode
is
39
# right
app/assets/stylesheets/common.scss
View file @
4398bdf2
...
...
@@ -57,6 +57,9 @@ table a code {
background
:
url(ajax_loader.gif)
no-repeat
center
center
;
width
:
40px
;
height
:
40px
;
&
.loading-gray
{
background
:
url(ajax_loader_gray.gif)
no-repeat
center
center
;
}
}
/** FLASH message **/
...
...
app/controllers/projects_controller.rb
View file @
4398bdf2
...
...
@@ -87,9 +87,13 @@ class ProjectsController < ProjectResourceController
end
def
graph
respond_to
do
|
format
|
format
.
html
format
.
json
do
graph
=
Gitlab
::
Graph
::
JsonBuilder
.
new
(
project
)
@days_json
,
@commits_json
=
graph
.
days_json
,
graph
.
commits_json
render
:json
=>
graph
.
to_json
end
end
end
def
destroy
...
...
app/views/projects/graph.html.haml
View file @
4398bdf2
...
...
@@ -2,13 +2,15 @@
%br
.graph_holder
%h4
%small
You can move around the graph by using arrow keys.
%small
You can move around the graph by using
the
arrow keys.
#holder
.graph
.loading.loading-gray
:javascript
var
chunk1
=
{
commits
:
#{
@commits_json
}
};
var
days
=
#{
@days_json
}
;
initGraph
();
var
branch_graph
;
$
(
function
(){
branchGraph
(
$
(
"
#holder
"
)[
0
]);
GraphNav
.
init
();
branch_graph
=
new
BranchGraph
(
$
(
"
#holder
"
),
{
url
:
'
#{
url_for
controller:
'projects'
,
action:
'graph'
,
format: :json
}
'
,
commit_url
:
'
#{
url_for
controller:
'projects'
,
action:
'show'
}
/commits/%s
'
});
});
lib/gitlab/graph/commit.rb
View file @
4398bdf2
...
...
@@ -28,7 +28,7 @@ module Gitlab
h
[
:refs
]
=
refs
.
collect
{
|
r
|
r
.
name
}.
join
(
" "
)
unless
refs
.
nil?
h
[
:id
]
=
sha
h
[
:date
]
=
date
h
[
:message
]
=
escape_once
(
message
)
h
[
:message
]
=
message
h
[
:login
]
=
author
.
email
h
end
...
...
lib/gitlab/graph/json_builder.rb
View file @
4398bdf2
...
...
@@ -18,12 +18,11 @@ module Gitlab
@days
=
index_commits
end
def
days_json
@days_json
=
@days
.
compact
.
map
{
|
d
|
[
d
.
day
,
d
.
strftime
(
"%b"
)]
}.
to_json
end
def
commits_json
@commits_json
=
@commits
.
map
(
&
:to_graph_hash
).
to_json
def
to_json
(
*
args
)
{
days:
@days
.
compact
.
map
{
|
d
|
[
d
.
day
,
d
.
strftime
(
"%b"
)]
},
commits:
@commits
.
map
(
&
:to_graph_hash
)
}.
to_json
(
*
args
)
end
protected
...
...
vendor/assets/javascripts/branch-graph.js
View file @
4398bdf2
var
commits
=
{},
comms
=
{},
pixelsX
=
[],
pixelsY
=
[],
mmax
=
Math
.
max
,
mtime
=
0
,
mspace
=
0
,
parents
=
{},
ii
=
0
,
colors
=
[
"
#000
"
];
function
initGraph
(){
commits
=
chunk1
.
commits
;
ii
=
commits
.
length
;
for
(
var
i
=
0
;
i
<
ii
;
i
++
)
{
for
(
var
j
=
0
,
jj
=
commits
[
i
].
parents
.
length
;
j
<
jj
;
j
++
)
{
parents
[
commits
[
i
].
parents
[
j
][
0
]]
=
true
;
}
mtime
=
Math
.
max
(
mtime
,
commits
[
i
].
time
);
mspace
=
Math
.
max
(
mspace
,
commits
[
i
].
space
);
}
mtime
=
mtime
+
4
;
mspace
=
mspace
+
10
;
for
(
i
=
0
;
i
<
ii
;
i
++
)
{
if
(
commits
[
i
].
id
in
parents
)
{
commits
[
i
].
isParent
=
true
;
}
comms
[
commits
[
i
].
id
]
=
commits
[
i
];
}
for
(
var
k
=
0
;
k
<
mspace
;
k
++
)
{
colors
.
push
(
Raphael
.
getColor
());
}
}
function
branchGraph
(
holder
)
{
var
ch
=
mspace
*
20
+
20
,
cw
=
mtime
*
20
+
20
,
r
=
Raphael
(
"
holder
"
,
cw
,
ch
),
top
=
r
.
set
();
var
cuday
=
0
,
cumonth
=
""
;
r
.
rect
(
0
,
0
,
days
.
length
*
20
+
80
,
30
).
attr
({
fill
:
"
#222
"
});
r
.
rect
(
0
,
30
,
days
.
length
*
20
+
80
,
20
).
attr
({
fill
:
"
#444
"
});
for
(
mm
=
0
;
mm
<
days
.
length
;
mm
++
)
{
if
(
days
[
mm
]
!=
null
){
if
(
cuday
!=
days
[
mm
][
0
]){
r
.
text
(
10
+
mm
*
20
,
40
,
days
[
mm
][
0
]).
attr
({
font
:
"
14px Fontin-Sans, Arial
"
,
fill
:
"
#DDD
"
});
cuday
=
days
[
mm
][
0
]
}
if
(
cumonth
!=
days
[
mm
][
1
]){
r
.
text
(
10
+
mm
*
20
,
15
,
days
[
mm
][
1
]).
attr
({
font
:
"
14px Fontin-Sans, Arial
"
,
fill
:
"
#EEE
"
});
cumonth
=
days
[
mm
][
1
]
}
}
}
for
(
i
=
0
;
i
<
ii
;
i
++
)
{
var
x
=
10
+
20
*
commits
[
i
].
time
,
y
=
70
+
20
*
commits
[
i
].
space
;
r
.
circle
(
x
,
y
,
3
).
attr
({
fill
:
colors
[
commits
[
i
].
space
],
stroke
:
"
none
"
});
if
(
commits
[
i
].
refs
!=
null
&&
commits
[
i
].
refs
!=
""
)
{
var
longrefs
=
commits
[
i
].
refs
var
shortrefs
=
commits
[
i
].
refs
;
!
function
(){
var
BranchGraph
=
function
(
element
,
options
){
this
.
element
=
element
;
this
.
options
=
options
;
this
.
preparedCommits
=
{};
this
.
mtime
=
0
;
this
.
mspace
=
0
;
this
.
parents
=
{};
this
.
colors
=
[
"
#000
"
];
this
.
load
();
};
BranchGraph
.
prototype
.
load
=
function
(){
$
.
ajax
({
url
:
this
.
options
.
url
,
method
:
'
get
'
,
dataType
:
'
json
'
,
success
:
$
.
proxy
(
function
(
data
){
$
(
'
.loading
'
,
this
.
element
).
hide
();
this
.
prepareData
(
data
.
days
,
data
.
commits
);
this
.
buildGraph
();
},
this
)
});
};
BranchGraph
.
prototype
.
prepareData
=
function
(
days
,
commits
){
this
.
days
=
days
;
this
.
dayCount
=
days
.
length
;
this
.
commits
=
commits
;
this
.
commitCount
=
commits
.
length
;
this
.
collectParents
();
this
.
mtime
+=
4
;
this
.
mspace
+=
10
;
for
(
var
i
=
0
;
i
<
this
.
commitCount
;
i
++
)
{
if
(
this
.
commits
[
i
].
id
in
this
.
parents
)
{
this
.
commits
[
i
].
isParent
=
true
;
}
this
.
preparedCommits
[
this
.
commits
[
i
].
id
]
=
this
.
commits
[
i
];
}
this
.
collectColors
();
};
BranchGraph
.
prototype
.
collectParents
=
function
(){
for
(
var
i
=
0
;
i
<
this
.
commitCount
;
i
++
)
{
for
(
var
j
=
0
,
jj
=
this
.
commits
[
i
].
parents
.
length
;
j
<
jj
;
j
++
)
{
this
.
parents
[
this
.
commits
[
i
].
parents
[
j
][
0
]]
=
true
;
}
this
.
mtime
=
Math
.
max
(
this
.
mtime
,
this
.
commits
[
i
].
time
);
this
.
mspace
=
Math
.
max
(
this
.
mspace
,
this
.
commits
[
i
].
space
);
}
};
BranchGraph
.
prototype
.
collectColors
=
function
(){
for
(
var
k
=
0
;
k
<
this
.
mspace
;
k
++
)
{
this
.
colors
.
push
(
Raphael
.
getColor
());
}
};
BranchGraph
.
prototype
.
buildGraph
=
function
(){
var
graphWidth
=
$
(
this
.
element
).
width
()
,
ch
=
this
.
mspace
*
20
+
20
,
cw
=
Math
.
max
(
graphWidth
,
this
.
mtime
*
20
+
20
)
,
r
=
Raphael
(
this
.
element
.
get
(
0
),
cw
,
ch
)
,
top
=
r
.
set
()
,
cuday
=
0
,
cumonth
=
""
,
offsetX
=
20
,
offsetY
=
60
,
barWidth
=
Math
.
max
(
graphWidth
,
this
.
dayCount
*
20
+
80
);
this
.
raphael
=
r
;
r
.
rect
(
0
,
0
,
barWidth
,
20
).
attr
({
fill
:
"
#222
"
});
r
.
rect
(
0
,
20
,
barWidth
,
20
).
attr
({
fill
:
"
#444
"
});
for
(
mm
=
0
;
mm
<
this
.
dayCount
;
mm
++
)
{
if
(
this
.
days
[
mm
]
!=
null
){
if
(
cuday
!=
this
.
days
[
mm
][
0
]){
// Dates
r
.
text
(
offsetX
+
mm
*
20
,
31
,
this
.
days
[
mm
][
0
]).
attr
({
font
:
"
12px Monaco, Arial
"
,
fill
:
"
#DDD
"
});
cuday
=
this
.
days
[
mm
][
0
];
}
if
(
cumonth
!=
this
.
days
[
mm
][
1
]){
// Months
r
.
text
(
offsetX
+
mm
*
20
,
11
,
this
.
days
[
mm
][
1
]).
attr
({
font
:
"
12px Monaco, Arial
"
,
fill
:
"
#EEE
"
});
cumonth
=
this
.
days
[
mm
][
1
];
}
}
}
for
(
i
=
0
;
i
<
this
.
commitCount
;
i
++
)
{
var
x
=
offsetX
+
20
*
this
.
commits
[
i
].
time
,
y
=
offsetY
+
20
*
this
.
commits
[
i
].
space
;
r
.
circle
(
x
,
y
,
3
).
attr
({
fill
:
this
.
colors
[
this
.
commits
[
i
].
space
],
stroke
:
"
none
"
});
if
(
this
.
commits
[
i
].
refs
!=
null
&&
this
.
commits
[
i
].
refs
!=
""
)
{
var
longrefs
=
this
.
commits
[
i
].
refs
,
shortrefs
=
this
.
commits
[
i
].
refs
;
if
(
shortrefs
.
length
>
15
){
shortrefs
=
shortrefs
.
substr
(
0
,
13
)
+
"
...
"
;
}
var
t
=
r
.
text
(
x
+
5
,
y
+
5
,
shortrefs
).
attr
({
font
:
"
12px Fontin-Sans, Arial
"
,
fill
:
"
#666
"
,
title
:
longrefs
,
cursor
:
"
pointer
"
,
rotation
:
"
90
"
});
var
t
=
r
.
text
(
x
+
5
,
y
+
8
,
shortrefs
).
attr
({
font
:
"
12px Monaco, Arial
"
,
fill
:
"
#666
"
,
title
:
longrefs
,
cursor
:
"
pointer
"
,
rotation
:
"
90
"
});
var
textbox
=
t
.
getBBox
();
t
.
translate
(
textbox
.
height
/-
4
,
textbox
.
width
/
2
);
t
.
translate
(
textbox
.
height
/-
4
,
textbox
.
width
/
2
);
}
for
(
var
j
=
0
,
jj
=
commits
[
i
].
parents
.
length
;
j
<
jj
;
j
++
)
{
var
c
=
comms
[
commits
[
i
].
parents
[
j
][
0
]];
var
c
;
for
(
var
j
=
0
,
jj
=
this
.
commits
[
i
].
parents
.
length
;
j
<
jj
;
j
++
)
{
c
=
this
.
preparedCommits
[
this
.
commits
[
i
].
parents
[
j
][
0
]];
if
(
c
)
{
var
cx
=
10
+
20
*
c
.
time
,
cy
=
70
+
20
*
c
.
space
;
if
(
c
.
space
==
commits
[
i
].
space
)
{
r
.
path
(
"
M
"
+
(
x
-
5
)
+
"
,
"
+
(
y
+
.
0001
)
+
"
L
"
+
(
15
+
20
*
c
.
time
)
+
"
,
"
+
(
y
+
.
0001
))
.
attr
({
stroke
:
colors
[
c
.
space
],
"
stroke-width
"
:
2
});
var
cx
=
offsetX
+
20
*
c
.
time
,
cy
=
offsetY
+
20
*
c
.
space
;
if
(
c
.
space
==
this
.
commits
[
i
].
space
)
{
r
.
path
([
"
M
"
,
x
,
y
,
"
L
"
,
x
-
20
*
(
c
.
time
+
1
),
y
]).
attr
({
stroke
:
this
.
colors
[
c
.
space
],
"
stroke-width
"
:
2
});
}
else
if
(
c
.
space
<
commits
[
i
].
space
)
{
}
else
if
(
c
.
space
<
this
.
commits
[
i
].
space
)
{
r
.
path
([
"
M
"
,
x
-
5
,
y
+
.
0001
,
"
l-5-2,0,4,5,-2C
"
,
x
-
5
,
y
,
x
-
17
,
y
+
2
,
x
-
20
,
y
-
5
,
"
L
"
,
cx
,
y
-
5
,
cx
,
cy
])
.
attr
({
stroke
:
colors
[
commits
[
i
].
space
],
"
stroke-width
"
:
2
});
.
attr
({
stroke
:
this
.
colors
[
this
.
commits
[
i
].
space
],
"
stroke-width
"
:
2
});
}
else
{
r
.
path
([
"
M
"
,
x
-
3
,
y
+
6
,
"
l-4,3,4,2,0,-5L
"
,
x
-
10
,
y
+
20
,
"
L
"
,
x
-
10
,
cy
,
cx
,
cy
])
.
attr
({
stroke
:
colors
[
c
.
space
],
"
stroke-width
"
:
2
});
.
attr
({
stroke
:
this
.
colors
[
c
.
space
],
"
stroke-width
"
:
2
});
}
}
}
(
function
(
c
,
x
,
y
)
{
top
.
push
(
r
.
circle
(
x
,
y
,
10
).
attr
({
fill
:
"
#000
"
,
opacity
:
0
,
cursor
:
"
pointer
"
})
.
click
(
function
(){
location
.
href
=
location
.
href
.
replace
(
"
graph
"
,
"
commit/
"
+
c
.
id
);
})
.
hover
(
function
()
{
var
s
=
r
.
text
(
100
,
100
,
c
.
author
+
"
\n
\n
"
+
c
.
id
+
"
\n
\n
"
+
c
.
message
).
attr
({
fill
:
"
#fff
"
});
this
.
popup
=
r
.
popupit
(
x
,
y
+
5
,
s
,
0
);
top
.
push
(
this
.
popup
.
insertBefore
(
this
));
},
function
()
{
this
.
popup
&&
this
.
popup
.
remove
()
&&
delete
this
.
popup
;
}));
}(
commits
[
i
],
x
,
y
));
this
.
appendAnchor
(
top
,
this
.
commits
[
i
],
x
,
y
);
}
top
.
toFront
();
var
hw
=
holder
.
offsetWidth
,
hh
=
holder
.
offsetHeight
,
v
=
r
.
rect
(
hw
-
8
,
0
,
4
,
Math
.
pow
(
hh
,
2
)
/
ch
,
2
).
attr
({
fill
:
"
#000
"
,
opacity
:
0
}),
h
=
r
.
rect
(
0
,
hh
-
8
,
Math
.
pow
(
hw
,
2
)
/
cw
,
4
,
2
).
attr
({
fill
:
"
#000
"
,
opacity
:
0
}),
bars
=
r
.
set
(
v
,
h
),
drag
,
dragger
=
function
(
e
)
{
if
(
drag
)
{
e
=
e
||
window
.
event
;
holder
.
scrollLeft
=
drag
.
sl
-
(
e
.
clientX
-
drag
.
x
);
holder
.
scrollTop
=
drag
.
st
-
(
e
.
clientY
-
drag
.
y
);
}
this
.
element
.
scrollLeft
(
cw
);
this
.
bindEvents
();
};
holder
.
onmousedown
=
function
(
e
)
{
e
=
e
||
window
.
event
;
drag
=
{
x
:
e
.
clientX
,
y
:
e
.
clientY
,
st
:
holder
.
scrollTop
,
sl
:
holder
.
scrollLeft
};
document
.
onmousemove
=
dragger
;
bars
.
animate
({
opacity
:
.
5
},
300
);
BranchGraph
.
prototype
.
bindEvents
=
function
(){
var
drag
=
{}
,
element
=
this
.
element
;
var
dragger
=
function
(
event
){
element
.
scrollLeft
(
drag
.
sl
-
(
event
.
clientX
-
drag
.
x
));
element
.
scrollTop
(
drag
.
st
-
(
event
.
clientY
-
drag
.
y
));
};
document
.
onmouseup
=
function
()
{
drag
=
false
;
document
.
onmousemove
=
null
;
bars
.
animate
({
opacity
:
0
},
300
);
element
.
on
({
mousedown
:
function
(
event
)
{
drag
=
{
x
:
event
.
clientX
,
y
:
event
.
clientY
,
st
:
element
.
scrollTop
(),
sl
:
element
.
scrollLeft
()
};
holder
.
scrollLeft
=
cw
;
};
Raphael
.
fn
.
popupit
=
function
(
x
,
y
,
set
,
dir
,
size
)
{
$
(
window
).
on
(
'
mousemove
'
,
dragger
);
}
});
$
(
window
).
on
({
mouseup
:
function
(){
//bars.animate({opacity: 0}, 300);
$
(
window
).
off
(
'
mousemove
'
,
dragger
);
},
keydown
:
function
(
event
){
if
(
event
.
keyCode
==
37
){
// left
element
.
scrollLeft
(
element
.
scrollLeft
()
-
50
);
}
if
(
event
.
keyCode
==
38
){
// top
element
.
scrollTop
(
element
.
scrollTop
()
-
50
);
}
if
(
event
.
keyCode
==
39
){
// right
element
.
scrollLeft
(
element
.
scrollLeft
()
+
50
);
}
if
(
event
.
keyCode
==
40
){
// bottom
element
.
scrollTop
(
element
.
scrollTop
()
+
50
);
}
}
});
};
BranchGraph
.
prototype
.
appendAnchor
=
function
(
top
,
c
,
x
,
y
)
{
var
r
=
this
.
raphael
,
options
=
this
.
options
,
anchor
;
anchor
=
r
.
circle
(
x
,
y
,
10
).
attr
({
fill
:
"
#000
"
,
opacity
:
0
,
cursor
:
"
pointer
"
})
.
click
(
function
(){
window
.
location
=
options
.
commit_url
.
replace
(
'
%s
'
,
c
.
id
);
})
.
hover
(
function
(){
var
text
=
r
.
text
(
100
,
100
,
c
.
author
+
"
\n
\n
"
+
c
.
id
+
"
\n
\n
"
+
c
.
message
).
attr
({
fill
:
"
#fff
"
});
this
.
popup
=
r
.
tooltip
(
x
,
y
+
5
,
text
,
0
);
top
.
push
(
this
.
popup
.
insertBefore
(
this
));
},
function
(){
this
.
popup
&&
this
.
popup
.
remove
()
&&
delete
this
.
popup
;
});
top
.
push
(
anchor
);
};
this
.
BranchGraph
=
BranchGraph
;
}(
this
);
Raphael
.
fn
.
tooltip
=
function
(
x
,
y
,
set
,
dir
,
size
)
{
dir
=
dir
==
null
?
2
:
dir
;
size
=
size
||
5
;
x
=
Math
.
round
(
x
);
y
=
Math
.
round
(
y
);
var
bb
=
set
.
getBBox
(),
w
=
Math
.
round
(
bb
.
width
/
2
),
h
=
Math
.
round
(
bb
.
height
/
2
),
dx
=
[
0
,
w
+
size
*
2
,
0
,
-
w
-
size
*
2
],
dy
=
[
-
h
*
2
-
size
*
3
,
-
h
-
size
,
0
,
-
h
-
size
],
p
=
[
"
M
"
,
x
-
dx
[
dir
],
y
-
dy
[
dir
],
"
l
"
,
-
size
,
(
dir
==
2
)
*
-
size
,
-
mmax
(
w
-
size
,
0
),
0
,
"
a
"
,
size
,
size
,
0
,
0
,
1
,
-
size
,
-
size
,
var
mmax
=
Math
.
max
,
bb
=
set
.
getBBox
()
,
w
=
Math
.
round
(
bb
.
width
/
2
)
,
h
=
Math
.
round
(
bb
.
height
/
2
)
,
dx
=
[
0
,
w
+
size
*
2
,
0
,
-
w
-
size
*
2
]
,
dy
=
[
-
h
*
2
-
size
*
3
,
-
h
-
size
,
0
,
-
h
-
size
]
,
p
=
[
"
M
"
,
x
-
dx
[
dir
],
y
-
dy
[
dir
],
"
l
"
,
-
size
,
(
dir
==
2
)
*
-
size
,
-
mmax
(
w
-
size
,
0
),
0
,
"
a
"
,
size
,
size
,
0
,
0
,
1
,
-
size
,
-
size
,
"
l
"
,
0
,
-
mmax
(
h
-
size
,
0
),
(
dir
==
3
)
*
-
size
,
-
size
,
(
dir
==
3
)
*
size
,
-
size
,
0
,
-
mmax
(
h
-
size
,
0
),
"
a
"
,
size
,
size
,
0
,
0
,
1
,
size
,
-
size
,
"
l
"
,
mmax
(
w
-
size
,
0
),
0
,
size
,
!
dir
*
-
size
,
size
,
!
dir
*
size
,
mmax
(
w
-
size
,
0
),
0
,
"
a
"
,
size
,
size
,
0
,
0
,
1
,
size
,
size
,
"
l
"
,
0
,
mmax
(
h
-
size
,
0
),
(
dir
==
1
)
*
size
,
size
,
(
dir
==
1
)
*
-
size
,
size
,
0
,
mmax
(
h
-
size
,
0
),
"
a
"
,
size
,
size
,
0
,
0
,
1
,
-
size
,
size
,
"
l
"
,
-
mmax
(
w
-
size
,
0
),
0
,
"
z
"
].
join
(
"
,
"
),
xy
=
[{
x
:
x
,
y
:
y
+
size
*
2
+
h
},
{
x
:
x
-
size
*
2
-
w
,
y
:
y
},
{
x
:
x
,
y
:
y
-
size
*
2
-
h
},
{
x
:
x
+
size
*
2
+
w
,
y
:
y
}][
dir
];
"
l
"
,
-
mmax
(
w
-
size
,
0
),
0
,
"
z
"
].
join
(
"
,
"
)
,
xy
=
[{
x
:
x
,
y
:
y
+
size
*
2
+
h
},
{
x
:
x
-
size
*
2
-
w
,
y
:
y
},
{
x
:
x
,
y
:
y
-
size
*
2
-
h
},
{
x
:
x
+
size
*
2
+
w
,
y
:
y
}][
dir
];
set
.
translate
(
xy
.
x
-
w
-
bb
.
x
,
xy
.
y
-
h
-
bb
.
y
);
return
this
.
set
(
this
.
path
(
p
).
attr
({
fill
:
"
#234
"
,
stroke
:
"
none
"
}).
insertBefore
(
set
.
node
?
set
:
set
[
0
]),
set
);
};
Raphael
.
fn
.
popup
=
function
(
x
,
y
,
text
,
dir
,
size
)
{
dir
=
dir
==
null
?
2
:
dir
>
3
?
3
:
dir
;
size
=
size
||
5
;
text
=
text
||
"
$9.99
"
;
var
res
=
this
.
set
(),
d
=
3
;
res
.
push
(
this
.
path
().
attr
({
fill
:
"
#000
"
,
stroke
:
"
#000
"
}));
res
.
push
(
this
.
text
(
x
,
y
,
text
).
attr
(
this
.
g
.
txtattr
).
attr
({
fill
:
"
#fff
"
,
"
font-family
"
:
"
Helvetica, Arial
"
}));
res
.
update
=
function
(
X
,
Y
,
withAnimation
)
{
X
=
X
||
x
;
Y
=
Y
||
y
;
var
bb
=
this
[
1
].
getBBox
(),
w
=
bb
.
width
/
2
,
h
=
bb
.
height
/
2
,
dx
=
[
0
,
w
+
size
*
2
,
0
,
-
w
-
size
*
2
],
dy
=
[
-
h
*
2
-
size
*
3
,
-
h
-
size
,
0
,
-
h
-
size
],
p
=
[
"
M
"
,
X
-
dx
[
dir
],
Y
-
dy
[
dir
],
"
l
"
,
-
size
,
(
dir
==
2
)
*
-
size
,
-
mmax
(
w
-
size
,
0
),
0
,
"
a
"
,
size
,
size
,
0
,
0
,
1
,
-
size
,
-
size
,
"
l
"
,
0
,
-
mmax
(
h
-
size
,
0
),
(
dir
==
3
)
*
-
size
,
-
size
,
(
dir
==
3
)
*
size
,
-
size
,
0
,
-
mmax
(
h
-
size
,
0
),
"
a
"
,
size
,
size
,
0
,
0
,
1
,
size
,
-
size
,
"
l
"
,
mmax
(
w
-
size
,
0
),
0
,
size
,
!
dir
*
-
size
,
size
,
!
dir
*
size
,
mmax
(
w
-
size
,
0
),
0
,
"
a
"
,
size
,
size
,
0
,
0
,
1
,
size
,
size
,
"
l
"
,
0
,
mmax
(
h
-
size
,
0
),
(
dir
==
1
)
*
size
,
size
,
(
dir
==
1
)
*
-
size
,
size
,
0
,
mmax
(
h
-
size
,
0
),
"
a
"
,
size
,
size
,
0
,
0
,
1
,
-
size
,
size
,
"
l
"
,
-
mmax
(
w
-
size
,
0
),
0
,
"
z
"
].
join
(
"
,
"
),
xy
=
[{
x
:
X
,
y
:
Y
+
size
*
2
+
h
},
{
x
:
X
-
size
*
2
-
w
,
y
:
Y
},
{
x
:
X
,
y
:
Y
-
size
*
2
-
h
},
{
x
:
X
+
size
*
2
+
w
,
y
:
Y
}][
dir
];
xy
.
path
=
p
;
if
(
withAnimation
)
{
this
.
animate
(
xy
,
500
,
"
>
"
);
}
else
{
this
.
attr
(
xy
);
}
return
this
;
};
return
res
.
update
(
x
,
y
);
};
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