(새 문서: →========================================= FrameGeometry 대문 사선 프레임 공통 정수 좌표계 =========================================: (function (w, document) { 'use strict'; var SVG_NS = 'http://www.w3.org/2000/svg'; var FRAME = { BORDER:1, BEVEL:1, SLANT_RISE:2, SLANT_RUN:1, BUTTON_FACE:20, FRAME_FACE:7, GAP:2, COLORS:{ border:'#050505', surface:'#1d1d1d',...) |
(Install package: clbiwiki-portal-frame-pixel-stack-20260717 / js/FrameGeometry.js) |
||
| 26번째 줄: | 26번째 줄: | ||
}; | }; | ||
var DIMENSIONS = { | var DIMENSIONS = { | ||
FRAME_SURFACE_TOP:FRAME.BORDER, | |||
FRAME_SURFACE_BOTTOM:FRAME.BORDER + FRAME.FRAME_FACE, | |||
WELL_TOP:FRAME.BORDER + FRAME.FRAME_FACE, | |||
WELL_BOTTOM:FRAME.BORDER + FRAME.FRAME_FACE + FRAME.GAP, | |||
ROW_HEIGHT:FRAME.FRAME_FACE + FRAME.GAP + FRAME.BUTTON_FACE + FRAME.GAP + FRAME.FRAME_FACE, | BUTTON_EDGE_TOP:FRAME.BORDER + FRAME.FRAME_FACE + FRAME.GAP, | ||
BUTTON_SURFACE_TOP:FRAME.BORDER + FRAME.FRAME_FACE + FRAME.GAP + FRAME.BORDER, | |||
BUTTON_SURFACE_BOTTOM:FRAME.BORDER + FRAME.FRAME_FACE + FRAME.GAP + FRAME.BORDER + FRAME.BUTTON_FACE, | |||
BUTTON_EDGE_BOTTOM:FRAME.BORDER + FRAME.FRAME_FACE + FRAME.GAP + FRAME.BORDER + FRAME.BUTTON_FACE + FRAME.BORDER, | |||
WELL2_TOP:FRAME.BORDER + FRAME.FRAME_FACE + FRAME.GAP + FRAME.BORDER + FRAME.BUTTON_FACE + FRAME.BORDER, | |||
WELL2_BOTTOM:FRAME.BORDER + FRAME.FRAME_FACE + FRAME.GAP + FRAME.BORDER + FRAME.BUTTON_FACE + FRAME.BORDER + FRAME.GAP, | |||
FRAME2_SURFACE_TOP:FRAME.BORDER + FRAME.FRAME_FACE + FRAME.GAP + FRAME.BORDER + FRAME.BUTTON_FACE + FRAME.BORDER + FRAME.GAP, | |||
FRAME2_SURFACE_BOTTOM:FRAME.BORDER + FRAME.FRAME_FACE + FRAME.GAP + FRAME.BORDER + FRAME.BUTTON_FACE + FRAME.BORDER + FRAME.GAP + FRAME.FRAME_FACE, | |||
ROW_HEIGHT:FRAME.BORDER + FRAME.FRAME_FACE + FRAME.GAP + FRAME.BORDER + FRAME.BUTTON_FACE + FRAME.BORDER + FRAME.GAP + FRAME.FRAME_FACE + FRAME.BORDER, | |||
OVERLAP:FRAME.FRAME_FACE + FRAME.GAP | OVERLAP:FRAME.FRAME_FACE + FRAME.GAP | ||
}; | }; | ||
/* 기존 소비 파일의 이름은 정본 좌표에 대한 별칭으로만 유지한다. */ | |||
DIMENSIONS.TOP_FRAME = DIMENSIONS.FRAME_SURFACE_BOTTOM; | |||
DIMENSIONS.BUTTON_TOP = DIMENSIONS.BUTTON_EDGE_TOP; | |||
DIMENSIONS.BUTTON_BOTTOM = DIMENSIONS.BUTTON_EDGE_BOTTOM; | |||
DIMENSIONS.BOTTOM_FRAME = DIMENSIONS.ROW_HEIGHT - DIMENSIONS.FRAME2_SURFACE_TOP; | |||
DIMENSIONS.BUTTON_TOTAL = DIMENSIONS.BUTTON_EDGE_BOTTOM - DIMENSIONS.BUTTON_EDGE_TOP; | |||
var listeners = []; | var listeners = []; | ||
| 67번째 줄: | 82번째 줄: | ||
[integer(slantX(rightTopX, bottomY, rightDir, phase) - rightInset), integer(bottomY)], | [integer(slantX(rightTopX, bottomY, rightDir, phase) - rightInset), integer(bottomY)], | ||
[integer(slantX(leftTopX, bottomY, leftDir, phase) + leftInset), integer(bottomY)] | [integer(slantX(leftTopX, bottomY, leftDir, phase) + leftInset), integer(bottomY)] | ||
]; | |||
} | |||
function rowAt(leftTopX, rightTopX, y, leftDir, rightDir, phase, leftInset, rightInset) { | |||
leftInset = integer(leftInset || 0); | |||
rightInset = integer(rightInset || 0); | |||
return [ | |||
[integer(slantX(leftTopX, y, leftDir, phase) + leftInset), integer(y)], | |||
[integer(slantX(rightTopX, y, rightDir, phase) - rightInset), integer(y)] | |||
]; | ]; | ||
} | } | ||
| 163번째 줄: | 187번째 줄: | ||
segment:segment, | segment:segment, | ||
segmentAt:segmentAt, | segmentAt:segmentAt, | ||
rowAt:rowAt, | |||
pts:pts, | pts:pts, | ||
create:create, | create:create, | ||
2026년 7월 17일 (금) 12:00 판
/* =========================================
FrameGeometry
대문 사선 프레임 공통 정수 좌표계
========================================= */
(function (w, document) {
'use strict';
var SVG_NS = 'http://www.w3.org/2000/svg';
var FRAME = {
BORDER:1,
BEVEL:1,
SLANT_RISE:2,
SLANT_RUN:1,
BUTTON_FACE:20,
FRAME_FACE:7,
GAP:2,
COLORS:{
border:'#050505',
surface:'#1d1d1d',
well:'#080808',
highlight:'#555555',
shadow:'#101010',
label:'#e2e2e2'
}
};
var DIMENSIONS = {
FRAME_SURFACE_TOP:FRAME.BORDER,
FRAME_SURFACE_BOTTOM:FRAME.BORDER + FRAME.FRAME_FACE,
WELL_TOP:FRAME.BORDER + FRAME.FRAME_FACE,
WELL_BOTTOM:FRAME.BORDER + FRAME.FRAME_FACE + FRAME.GAP,
BUTTON_EDGE_TOP:FRAME.BORDER + FRAME.FRAME_FACE + FRAME.GAP,
BUTTON_SURFACE_TOP:FRAME.BORDER + FRAME.FRAME_FACE + FRAME.GAP + FRAME.BORDER,
BUTTON_SURFACE_BOTTOM:FRAME.BORDER + FRAME.FRAME_FACE + FRAME.GAP + FRAME.BORDER + FRAME.BUTTON_FACE,
BUTTON_EDGE_BOTTOM:FRAME.BORDER + FRAME.FRAME_FACE + FRAME.GAP + FRAME.BORDER + FRAME.BUTTON_FACE + FRAME.BORDER,
WELL2_TOP:FRAME.BORDER + FRAME.FRAME_FACE + FRAME.GAP + FRAME.BORDER + FRAME.BUTTON_FACE + FRAME.BORDER,
WELL2_BOTTOM:FRAME.BORDER + FRAME.FRAME_FACE + FRAME.GAP + FRAME.BORDER + FRAME.BUTTON_FACE + FRAME.BORDER + FRAME.GAP,
FRAME2_SURFACE_TOP:FRAME.BORDER + FRAME.FRAME_FACE + FRAME.GAP + FRAME.BORDER + FRAME.BUTTON_FACE + FRAME.BORDER + FRAME.GAP,
FRAME2_SURFACE_BOTTOM:FRAME.BORDER + FRAME.FRAME_FACE + FRAME.GAP + FRAME.BORDER + FRAME.BUTTON_FACE + FRAME.BORDER + FRAME.GAP + FRAME.FRAME_FACE,
ROW_HEIGHT:FRAME.BORDER + FRAME.FRAME_FACE + FRAME.GAP + FRAME.BORDER + FRAME.BUTTON_FACE + FRAME.BORDER + FRAME.GAP + FRAME.FRAME_FACE + FRAME.BORDER,
OVERLAP:FRAME.FRAME_FACE + FRAME.GAP
};
/* 기존 소비 파일의 이름은 정본 좌표에 대한 별칭으로만 유지한다. */
DIMENSIONS.TOP_FRAME = DIMENSIONS.FRAME_SURFACE_BOTTOM;
DIMENSIONS.BUTTON_TOP = DIMENSIONS.BUTTON_EDGE_TOP;
DIMENSIONS.BUTTON_BOTTOM = DIMENSIONS.BUTTON_EDGE_BOTTOM;
DIMENSIONS.BOTTOM_FRAME = DIMENSIONS.ROW_HEIGHT - DIMENSIONS.FRAME2_SURFACE_TOP;
DIMENSIONS.BUTTON_TOTAL = DIMENSIONS.BUTTON_EDGE_BOTTOM - DIMENSIONS.BUTTON_EDGE_TOP;
var listeners = [];
DIMENSIONS.BOTTOM_START_ABS_Y = DIMENSIONS.ROW_HEIGHT - DIMENSIONS.OVERLAP;
function integer(value) {
return Math.round(Number(value) || 0);
}
function snapWidth(raw) {
return Math.floor(Number(raw) || 0);
}
function slantX(xTop, y, dir, phase) {
phase = phase || 0;
return xTop + dir * Math.floor((y + phase) / FRAME.SLANT_RISE) * FRAME.SLANT_RUN;
}
function segment(leftTopX, rightTopX, height, leftDir, rightDir, phase) {
return [
[integer(leftTopX), 0],
[integer(rightTopX), 0],
[integer(slantX(rightTopX, height, rightDir, phase)), integer(height)],
[integer(slantX(leftTopX, height, leftDir, phase)), integer(height)]
];
}
function segmentAt(leftTopX, rightTopX, topY, bottomY, leftDir, rightDir, phase, leftInset, rightInset) {
leftInset = integer(leftInset || 0);
rightInset = integer(rightInset || 0);
return [
[integer(slantX(leftTopX, topY, leftDir, phase) + leftInset), integer(topY)],
[integer(slantX(rightTopX, topY, rightDir, phase) - rightInset), integer(topY)],
[integer(slantX(rightTopX, bottomY, rightDir, phase) - rightInset), integer(bottomY)],
[integer(slantX(leftTopX, bottomY, leftDir, phase) + leftInset), integer(bottomY)]
];
}
function rowAt(leftTopX, rightTopX, y, leftDir, rightDir, phase, leftInset, rightInset) {
leftInset = integer(leftInset || 0);
rightInset = integer(rightInset || 0);
return [
[integer(slantX(leftTopX, y, leftDir, phase) + leftInset), integer(y)],
[integer(slantX(rightTopX, y, rightDir, phase) - rightInset), integer(y)]
];
}
function pts(points) {
return points.map(function (point) {
return integer(point[0]) + ',' + integer(point[1]);
}).join(' ');
}
function create(name, className) {
var node = document.createElementNS(SVG_NS, name);
if (className) node.setAttribute('class', className);
node.setAttribute('shape-rendering', 'crispEdges');
return node;
}
function polygon(className, points) {
var node = create('polygon', className);
node.setAttribute('points', pts(points));
node.setAttribute('pointer-events', 'none');
return node;
}
function line(className, start, end) {
var node = create('line', className);
node.setAttribute('x1', integer(start[0]));
node.setAttribute('y1', integer(start[1]));
node.setAttribute('x2', integer(end[0]));
node.setAttribute('y2', integer(end[1]));
node.setAttribute('vector-effect', 'non-scaling-stroke');
node.setAttribute('pointer-events', 'none');
return node;
}
function rect(className, x, y, width, height) {
var node = create('rect', className);
node.setAttribute('x', integer(x));
node.setAttribute('y', integer(y));
node.setAttribute('width', Math.max(0, integer(width)));
node.setAttribute('height', Math.max(0, integer(height)));
node.setAttribute('pointer-events', 'none');
return node;
}
function centerX(points) {
return integer((points[0][0] + points[1][0] + points[2][0] + points[3][0]) / 4);
}
function readWidth(node) {
if (!node) return 0;
return snapWidth(node.clientWidth || node.offsetWidth || 0);
}
function setSeams(next) {
var frame = w.CLBI.frame;
var copy = {};
Object.keys(next || {}).forEach(function (key) {
copy[key] = next[key];
});
copy.revision = integer((frame.seams && frame.seams.revision) || 0) + 1;
frame.seams = copy;
listeners.slice().forEach(function (listener) {
try { listener(copy); } catch (error) {}
});
try {
document.dispatchEvent(new CustomEvent('framegeometryseams', { detail:copy }));
} catch (error) {}
if (w.mw && w.mw.hook) {
w.mw.hook('frame.geometry.seams').fire(copy);
}
return copy;
}
function onSeams(listener) {
if (typeof listener !== 'function') return function () {};
listeners.push(listener);
if (w.CLBI.frame.seams && w.CLBI.frame.seams.width) {
listener(w.CLBI.frame.seams);
}
return function () {
var index = listeners.indexOf(listener);
if (index !== -1) listeners.splice(index, 1);
};
}
w.CLBI = w.CLBI || {};
w.CLBI.frame = {
FRAME:FRAME,
DIMENSIONS:DIMENSIONS,
slantX:slantX,
segment:segment,
segmentAt:segmentAt,
rowAt:rowAt,
pts:pts,
create:create,
polygon:polygon,
line:line,
rect:rect,
centerX:centerX,
snapWidth:snapWidth,
readWidth:readWidth,
setSeams:setSeams,
onSeams:onSeams,
seams:{}
};
}(window, document));