2023-09-09 12:04:55 -04:00
var currently _dragging = null ; // if this is null, we have nothing being dragged. if it's not null, then it will represent the glyph object (as goes in the glyphs array) which is currently being dragged
var major _radius ;
const glyphs = [ ] ;
2023-09-12 23:00:04 -04:00
const vowels = [ ] ;
const consonants = [ ] ;
2023-09-09 12:04:55 -04:00
2024-09-10 13:19:40 -04:00
var svg ;
var connections _container ;
2023-09-09 12:04:55 -04:00
$ ( document ) . ready ( function ( ) {
svg = $ ( 'svg#arena' ) [ 0 ] ;
2024-09-10 13:19:40 -04:00
connections _container = $ ( 'svg#arena #connections' ) ;
2023-09-09 12:04:55 -04:00
major _radius = parseFloat ( $ ( 'circle' ) . attr ( 'r' ) ) ;
$ ( document ) . on ( "mouseup" , on _mouse _up ) ;
2023-09-12 23:00:04 -04:00
$ ( 'td > svg' ) . on ( "mousedown" , function ( event ) {
2023-09-09 12:04:55 -04:00
let receptacle = $ ( "#consonant_put_it_in_here" ) ;
let selected = $ ( this ) ;
receptacle . html ( selected . html ( ) ) ;
2023-09-12 23:00:04 -04:00
const mouse _position = svg _from _dom ( { x : event . clientX , y : event . clientY } , svg ) ;
2024-09-10 13:19:40 -04:00
var g = make _new _consonant ( ) ;
set _location ( g , mouse _position ) ;
2023-09-12 23:00:04 -04:00
currently _dragging = g ;
} )
$ ( '.vowel-example > svg' ) . on ( "mousedown" , function ( event ) {
2023-09-09 12:04:55 -04:00
let receptacle = $ ( '#vowel_put_it_in_here' ) ;
let selected = $ ( this ) ;
receptacle . html ( selected . html ( ) ) ;
2023-09-12 23:00:04 -04:00
2024-09-10 13:19:40 -04:00
var g = make _new _vowel ( ) ;
2023-09-12 23:00:04 -04:00
const mouse _position = svg _from _dom ( { x : event . clientX , y : event . clientY } , svg ) ;
2024-09-10 13:19:40 -04:00
set _location ( g , mouse _position ) ;
2023-09-09 12:04:55 -04:00
2023-09-12 23:00:04 -04:00
currently _dragging = g ;
2023-09-09 12:04:55 -04:00
} ) ;
2023-09-12 23:00:04 -04:00
$ ( 'td > svg' ) . each ( function ( ) { this . setAttribute ( 'viewBox' , "0 30 40 100" ) ; } ) ;
2023-09-09 12:04:55 -04:00
populate _consonant _grid ( ) ;
2023-09-12 23:00:04 -04:00
populate _vowels ( ) ;
2023-09-09 12:04:55 -04:00
} ) ;
function populate _consonant _grid ( ) {
// this function expects that there's a #consonant-grid table, where each row corresponds to a glyph set
// the cells of the row need to be filled with the various possible configurations of that glyph
// so like, the <th> in a given row should contain a .megaglyph svg group, which contains the base glyph plus all possible radicals.
// then we use the split_megaglyph function to generate the five possible configurations out of that megaglyph
// and insert the five configured glyphs into their corresponding (td) cells of the table
$ ( "#consonant-grid tbody tr" ) . each ( function ( asdf , row ) { // iterate over the rows in the table
// row will now be something like <tr><th/><td/><td/><td/><td/><td/><th/></tr>
// that is, a tr containing one th on either end plus a td for each consonant in this row
var head = $ ( row ) . find ( "th:first-child svg" ) ; // this is the header for the row, which should contain the .megaglyph object
var megaglyph = head . find ( ".megaglyph" ) ;
var glyphs = split _megaglyph ( megaglyph ) ; // now this is a list of the configured consonant symbols
$ ( row ) . find ( "td" ) . each ( function ( idx , cell ) { // iterate over the cells in the row
// cell will now be a <td> cell which contains the IPA for that cell's consonants, plus the <svg> canvas into which to insert the configured consonant symbol
$ ( cell ) . find ( "svg" ) . append ( glyphs [ idx ] ) ;
} ) ;
} ) ;
}
function split _megaglyph ( megaglyph ) {
// megaglyph is an svg object which contains all the possible radicals at once.
// this should return a list of new glyphs, cloned frmo megaglyph, each of which contains only the radicals it wants.
var one = megaglyph . clone ( ) ;
one . find ( '.line_1,.line_2,.line_3,.dot_2,.dot_3' ) . remove ( ) ; // only .dot_1
remove _class ( one , "megaglyph" ) ;
var two = megaglyph . clone ( ) ;
two . find ( '.line_2,.line_3,.dot_1,.dot_2,.dot_3' ) . remove ( ) ; // line 1 only
remove _class ( two , "megaglyph" ) ;
var three = megaglyph . clone ( ) ;
three . find ( '.line_1,.line_2,.line_3,.dot_1' ) . remove ( ) ; // only dots 2 and 3
remove _class ( three , "megaglyph" ) ;
var four = megaglyph . clone ( ) ;
four . find ( '.line_1,.dot_1,.dot_2,.dot_3' ) . remove ( ) ; //lines 2 and 3
remove _class ( four , "megaglyph" ) ;
var five = megaglyph . clone ( ) ;
five . find ( '.line_1,.line_2,.line_3' ) . remove ( ) ; // all three dots
remove _class ( five , "megaglyph" ) ;
return [ one , two , three , four , five ] ;
}
2023-09-12 23:00:04 -04:00
function populate _vowels ( ) {
megaglyph = $ ( ".vowel.megaglyph" ) ;
$ ( ".vowel-example svg" ) . each ( ( i , ex ) => {
let glyphs = $ ( ex ) . text ( ) . replace ( /(\s|\n)+/g , "," ) . split ( "," ) . filter ( ( a ) => a != "" )
$ ( ex ) . text ( "" ) ;
$ . each ( glyphs , ( i , e ) => {
let wanted _class = "." + e ;
let glyph _original = megaglyph . find ( wanted _class ) ;
let new _glyph = glyph _original . clone ( ) ;
$ ( ex ) . append ( new _glyph ) ;
} ) ;
} ) ;
}
2023-09-09 12:04:55 -04:00
2023-09-12 23:00:04 -04:00
function make _new _consonant ( source ) {
// create a new glyph object by copying the elements pointed to by source
// this will add it to the svg and to the glyphs list
var x = { } ;
x . angle = 0 ;
2024-09-10 13:19:40 -04:00
x . element = $ ( "#consonant_copy_from_here" ) . clone ( ) . attr ( "id" , "" ) . attr ( "onclick" , "" ) . attr ( "onmousedown" , "" ) ;
2023-09-12 23:00:04 -04:00
x . element . find ( "#consonant_put_it_in_here" ) . attr ( "id" , "" ) ;
x . position = { x : 0 , y : 0 } ;
2024-09-10 13:19:40 -04:00
x . element . on ( "mousedown" , x , ( event ) => { currently _dragging = event . data } ) ;
2023-09-12 23:00:04 -04:00
$ ( svg ) . append ( x . element ) ;
2023-09-09 12:04:55 -04:00
2023-09-12 23:00:04 -04:00
x . handles = [ ] ;
2024-09-10 13:19:40 -04:00
x . handles . push ( $ ( ns _elem ( "circle" , svg _ns ) ) )
x . handles . push ( $ ( ns _elem ( "circle" , svg _ns ) ) )
$ . each ( x . handles , function ( ) {
$ ( svg ) . append ( this )
this . attr ( "r" , 2 ) ;
add _class ( this , "handle" ) ;
} ) ;
2023-09-12 23:00:04 -04:00
update _handles ( x ) ;
glyphs . push ( x ) ;
2024-09-10 13:19:40 -04:00
x . vowel = false ;
2023-09-12 23:00:04 -04:00
return x ;
2023-09-09 12:04:55 -04:00
}
2024-09-10 13:19:40 -04:00
function make _new _vowel ( source ) {
2023-09-09 12:04:55 -04:00
// create a new glyph object by copying the elements pointed to by source
// this will add it to the svg and to the glyphs list
var x = { } ;
x . angle = 0 ;
2024-09-10 13:19:40 -04:00
x . element = $ ( "#vowel_copy_from_here" ) . clone ( ) . attr ( "id" , "" ) . attr ( "onclick" , "" ) . attr ( "onmousedown" , "" ) ;
2023-09-12 23:00:04 -04:00
x . element . find ( "#vowel_put_it_in_here" ) . attr ( "id" , "" ) ;
2023-09-09 12:04:55 -04:00
x . position = { x : 0 , y : 0 } ;
2024-09-10 13:19:40 -04:00
x . element . on ( "mousedown" , x , ( event ) => { currently _dragging = event . data } ) ;
2023-09-09 12:04:55 -04:00
$ ( svg ) . append ( x . element ) ;
2023-09-12 23:00:04 -04:00
x . handles = [ ] ;
2024-09-10 13:19:40 -04:00
x . handles . push ( $ ( ns _elem ( "circle" , svg _ns ) ) ) ;
x . handles . push ( $ ( ns _elem ( "circle" , svg _ns ) ) ) ;
$ . each ( x . handles , function ( ) {
$ ( svg ) . append ( this )
this . attr ( "r" , 2 ) ;
add _class ( this , "handle" ) ;
} ) ;
2023-09-12 23:00:04 -04:00
update _handles ( x ) ;
2023-09-09 12:04:55 -04:00
glyphs . push ( x ) ;
2024-09-10 13:19:40 -04:00
x . vowel = true ;
2023-09-09 12:04:55 -04:00
return x ;
}
function on _mouse _up ( event ) {
// this is called on the whole document when the mouse is released on it. event.data is meaningless. this should handle releasing the current dragged element, if it exists.
if ( currently _dragging != null && is _in _delete _region ( currently _dragging . position ) ) {
remove ( glyphs , currently _dragging ) ;
2023-09-12 23:00:04 -04:00
$ . each ( currently _dragging . handles , function ( ) { $ ( this ) . remove ( ) ; } ) ;
2023-09-09 12:04:55 -04:00
currently _dragging . element . remove ( ) ;
currently _dragging = null ;
2024-09-10 13:19:40 -04:00
connect _vowels ( ) ;
2023-09-09 12:04:55 -04:00
}
if ( currently _dragging != null ) {
2024-09-10 13:19:40 -04:00
set _location ( currently _dragging , mul ( norm ( currently _dragging . position ) , major _radius ) ) ;
2023-09-09 12:04:55 -04:00
}
currently _dragging = null ;
}
function is _in _delete _region ( p ) {
r = $ ( "#delete" ) ;
first = { x : parseFloat ( r . attr ( "x" ) ) , y : parseFloat ( r . attr ( "y" ) ) } ;
second = { x : parseFloat ( r . attr ( "width" ) ) + first . x , y : parseFloat ( r . attr ( "height" ) ) + first . y } ;
if ( p . x > first . x && p . x < second . x && p . y > first . y && p . y < second . y ) {
return true ;
}
return false ;
}
$ ( document ) . mousemove ( function ( event ) {
const mouse _position = svg _from _dom ( { x : event . clientX , y : event . clientY } , svg ) ;
const mouse _move = sub ( mouse _position , previous _mouse _position ) ;
previous _mouse _position = mouse _position ;
var s _position = mouse _position ;
// get the position inside the svg tag for the mouse
if ( currently _dragging != null ) {
2024-09-10 13:19:40 -04:00
set _location ( currently _dragging , add ( currently _dragging . position , mouse _move ) ) ;
2023-09-12 23:00:04 -04:00
update _handles ( currently _dragging ) ;
2023-09-09 12:04:55 -04:00
}
2023-09-12 23:00:04 -04:00
} ) ;
function update _handles ( g ) {
2024-09-10 13:19:40 -04:00
if ( g . element . find ( 'path.glyph,path.vowel-base' ) . length != 0 ) {
set _loc ( g . handles [ 0 ] , get _global _point _at _length ( svg , g . element . find ( 'path.glyph,path.vowel-base' ) [ 0 ] , 0 ) ) ;
set _loc ( g . handles [ 1 ] , get _global _point _at _length ( svg , g . element . find ( 'path.glyph,path.vowel-base' ) [ 0 ] , 1000 ) ) ;
}
connect _vowels ( ) ;
}
function set _location ( glyph , point ) {
glyph . position = point ;
glyph . angle = Math . atan2 ( point . y , point . x ) ;
set _transform ( glyph . element , glyph . position , appropriate _angle ( point ) ) ;
update _handles ( glyph ) ;
}
function connect _vowels ( ) {
let vowels = $ . grep ( glyphs , ( v ) => v . vowel ) ;
vowels . sort ( ( a , b ) => b . angle - a . angle ) ;
console . log ( $ . map ( vowels , ( a ) => a . angle ) ) ;
// clear oout the old connections
connections _container . html ( "" ) ;
if ( vowels . length == 0 ) {
// if there's no vowels, we should have just a bare circle
/ * } e l s e i f ( v o w e l s . l e n g t h = = 1 ) {
// make a fake point on the other side to connect
let connection = ns _elem ( "path" , svg _ns ) ;
add _class ( connection , "intervowel" ) ;
let path = ` M ${ start _x } ${ start _y } ` ;
path += ` A ${ } `
$ ( connection ) . attr ( "d" , ` M ${ start _x } ${ start _y } A ${ major _radius } ${ major _radius } 0 ${ sweep } ${ large } ${ end _x } ${ end _y } ` ) ;
connections _container . append ( connection ) ; * /
} else {
// otherwise iterate over them and connect one to the next
for ( let i = 0 ; i < vowels . length ; i ++ ) {
//connections_container.append($(ns_elem("circle", svg_ns)).attr("r",1).attr("cx",Math.cos(vowels[i].angle)*major_radius).attr("cy",major_radius*Math.sin(vowels[i].angle)));
let connection = ns _elem ( "path" , svg _ns ) ;
add _class ( connection , "intervowel" ) ;
let first = vowels [ i ] ;
let second = vowels [ ( i + 1 ) % vowels . length ] ;
let start _x = parseFloat ( first . handles [ 1 ] . attr ( "cx" ) ) ;
let start _y = parseFloat ( first . handles [ 1 ] . attr ( "cy" ) ) ;
/ * a b a n d o n e d q u a d r a t i c a p p r o a c h
let roundness = 0.2 * Math . abs ( first . angle - second . angle ) ;
roundness = first . angle > second . angle ? 1 : 0 ;
let s _dx = start _x + ( Math . sin ( first . angle ) * major _radius * roundness ) ;
let s _dy = start _y - ( Math . cos ( first . angle ) * major _radius * roundness ) ;
* /
let end _x = parseFloat ( second . handles [ 0 ] . attr ( "cx" ) ) ;
let end _y = parseFloat ( second . handles [ 0 ] . attr ( "cy" ) ) ;
/ *
let e _dx = end _x - ( Math . sin ( second . angle ) * major _radius * roundness ) ;
let e _dy = end _y + ( Math . cos ( second . angle ) * major _radius * roundness ) ;
// $(connection).attr("d", `M ${start_x} ${start_y} C ${s_dx} ${s_dy} ${e_dx} ${e_dy} ${end_x} ${end_y}`);
* /
let distance = - ( second . angle - first . angle ) ;
if ( vowels . length == 1 ) {
distance = 1.5 * Math . PI ;
}
let midpoint ;
let sweep = "0" ;
let large = "0" ;
if ( distance < 0 ) {
distance += 2 * Math . PI ;
}
if ( distance < Math . PI ) {
sweep = "0"
large = "0"
} else if ( distance < 2 * Math . PI ) {
sweep = "1"
large = "0"
}
$ ( connection ) . attr ( "d" , ` M ${ start _x } ${ start _y } A ${ major _radius } ${ major _radius } 0 ${ sweep } ${ large } ${ end _x } ${ end _y } ` ) ;
connections _container . append ( connection ) ;
}
}
2023-09-12 23:00:04 -04:00
}