167 lines
5 KiB
JavaScript
167 lines
5 KiB
JavaScript
function createCanvas(selector, width, height, spacing, mouseOver) {
|
|
const result = {
|
|
xsize: Math.ceil(width/spacing),
|
|
ysize: Math.ceil(height/spacing),
|
|
spacing: spacing,
|
|
undoStack: [],
|
|
redoStack: [],
|
|
undoFrame: null,
|
|
};
|
|
|
|
result.width = result.xsize*spacing;
|
|
result.height = result.ysize*spacing;
|
|
|
|
const svg = d3.select(selector).append("svg")
|
|
.attr("id", "canvas")
|
|
.attr("width", result.width)
|
|
.attr("height", result.height)
|
|
.style("background", "white");
|
|
const cells = svg.append("g").attr("id", "canvas-cells");
|
|
const lines = svg.append("g").attr("id", "canvas-lines");
|
|
for(let i = 0; i < result.ysize; i++) {
|
|
lines.append("line")
|
|
.style("stroke", "#888")
|
|
.attr("class", "line")
|
|
.attr("x1", 0)
|
|
.attr("x2", result.width)
|
|
.attr("y1", i*result.spacing)
|
|
.attr("y2", i*result.spacing);
|
|
}
|
|
for(let i = 0; i < result.xsize; i++) {
|
|
lines.append("line")
|
|
.style("stroke", "#888")
|
|
.attr("class", "line")
|
|
.attr("y1", 0)
|
|
.attr("y2", result.height)
|
|
.attr("x1", i*result.spacing)
|
|
.attr("x2", i*result.spacing);
|
|
}
|
|
svg.on("scroll", ()=>{});
|
|
svg.on("contextmenu", (event, d)=>{event.preventDefault();});
|
|
svg.on("mousedown", (event, d)=>{
|
|
window.mouseButton = event.button;
|
|
result.beginUndoFrame("draw");
|
|
mouseOver(d3.pointer(event));
|
|
});
|
|
svg.on("mousemove", (event, d)=>{
|
|
if(window.mouseButton !== null) {
|
|
mouseOver(d3.pointer(event));
|
|
}
|
|
});
|
|
svg.on("mouseup", (event, d)=>{
|
|
window.mouseButton = null;
|
|
result.endUndoFrame();
|
|
});
|
|
|
|
result.svg = svg;
|
|
|
|
result.beginUndoFrame = function(type) {
|
|
result.undoFrame = [];
|
|
}
|
|
|
|
result.endUndoFrame = function() {
|
|
if(result.undoFrame.length > 0) {
|
|
result.undoStack.push(result.undoFrame);
|
|
}
|
|
result.undoFrame = null;
|
|
}
|
|
|
|
result.undo = function() {
|
|
if(result.undoStack.length > 0) {
|
|
const frame = result.undoStack.pop();
|
|
for(const change of frame.reverse()) {
|
|
result.setCell(change.x, change.y, change.before);
|
|
}
|
|
result.redoStack.push(frame);
|
|
}
|
|
}
|
|
|
|
result.redo = function() {
|
|
if(result.redoStack.length > 0) {
|
|
const frame = result.redoStack.pop();
|
|
for(const change of frame) {
|
|
result.setCell(change.x, change.y, change.after);
|
|
}
|
|
result.undoStack.push(frame);
|
|
}
|
|
}
|
|
|
|
result.clear = function() {
|
|
result.beginUndoFrame();
|
|
for(let x = 0; x < result.xsize; x++) {
|
|
for(let y = 0; y < result.xsize; y++) {
|
|
result.setCell(x, y, null);
|
|
}
|
|
}
|
|
result.endUndoFrame();
|
|
}
|
|
|
|
result.setCell = function(x, y, color) {
|
|
const cell = d3.select("#cell-"+x+"-"+y);
|
|
if(color === null) {
|
|
if(cell.size() != 0) {
|
|
if(result.undoFrame){
|
|
result.undoFrame.push({
|
|
x: x,
|
|
y: y,
|
|
before: cell.style("fill"),
|
|
after: null
|
|
});
|
|
}
|
|
cell.remove();
|
|
}
|
|
} else {
|
|
if(cell.size() == 0) {
|
|
if(result.undoFrame){
|
|
result.undoFrame.push({
|
|
x: x,
|
|
y: y,
|
|
before: null,
|
|
after: color
|
|
});
|
|
}
|
|
d3.select("#canvas-cells").append("rect")
|
|
.style("stroke-width", 0)
|
|
.style("fill", color)
|
|
.attr("id", "cell-"+x+"-"+y)
|
|
.attr("x", x*result.spacing)
|
|
.attr("y", y*result.spacing)
|
|
.attr("width", result.spacing)
|
|
.attr("height", result.spacing);
|
|
} else {
|
|
if(cell.style("fill") == color) {
|
|
return;
|
|
}
|
|
if(result.undoFrame){
|
|
result.undoFrame.push({
|
|
x: x,
|
|
y: y,
|
|
before: cell.style("fill"),
|
|
after: color
|
|
});
|
|
}
|
|
cell.style("fill", color);
|
|
}
|
|
}
|
|
}
|
|
|
|
result.setbg = function(color) {
|
|
svg.style("background", color);
|
|
}
|
|
|
|
result.setlinecol = function(color) {
|
|
const lines = d3.selectAll(".line");
|
|
if(color !== null) {
|
|
lines.style("stroke", color);
|
|
} else {
|
|
const cur = lines.attr("visibility");
|
|
if(cur == "hidden") {
|
|
lines.attr("visibility", null);
|
|
} else {
|
|
lines.attr("visibility", "hidden");
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|