Ok, give this a try: Just create a character named "Template: <something>" or "Guide: <something>", then set a template token to represent it, and set it as the default token for the character. When you want to use it, just drag it out onto a token, it will adjust its position and rotation to the targeted token. Here's the code: on('ready',()=>{
const isOverlappedDist = (obj1, obj2) => {
let dx = Math.abs(obj1.get('left')-obj2.get('left'));
let dy = Math.abs(obj1.get('top')-obj2.get('top'));
let lx = ((0+obj1.get('width') + obj2.get('width'))/2);
let ly = ((0+obj1.get('height') + obj2.get('height'))/2);
if(dx < lx && dy < ly){
return (dy*dy+dx*dx);
}
return false;
};
const findTargetToken = (obj) => findObjs({
type: 'graphic',
layer: obj.get('layer'),
pageid: obj.get('pageid')
})
.filter((o) => o.id !== obj.id)
.map(o=> ({overlap: isOverlappedDist(obj,o), token: o}))
.filter((o) => false !== o.overlap)
.sort((a,b)=>a.overlap-b.overlap);
const getTopTokenForPage = (tokens, pid) => {
let page = getObj('page',pid);
if(page){
let ids = tokens.map(t=>t.id);
let id = page.get('zorder').split(/,/).filter( id => ids.includes(id)).pop();
if(id){
let token = tokens.find(t => t.id===id);
if(token){
return token;
}
}
}
return tokens[0]; // in an error, return the first token in the list
};
on('add:graphic',(obj)=>{
let character = getObj('character',obj.get('represents'));
if(character){
let match =(character||{get:()=>''}).get('name').match(/^\s*(template|guide)\s*:/i);
if(match){
let toks = findTargetToken(obj);
let token = [toks[0]||{}].token;
if(toks.length>1){
let tList = toks.filter(o => o.overlap === toks[0].overlap).map(o=>o.token);
token = getTopTokenForPage(tList,obj.get('pageid'));
}
if(token){
obj.set({
rotation: token.get('rotation'),
left: token.get('left'),
top: token.get('top')
});
toBack(obj);
}
}
}
});
});