Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README-params.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ die("ok")
```
のように指定する必要があるため、対応していないPHPで、このフラグをtrueにすると投稿できなくなってしまいます。
そのため**デフォルトは false です**。

- **<PARAM NAME="neo_enable_zoom_out" VALUE="true">**
このフラグを true にするとズームで、0.5倍、0.2倍に縮小表示できるようになります。
オリジナルのPaintBBSには無い機能なので**デフォルトは false です**。

# 動画の仕様の違い

Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ NEO の入っていない掲示板に投稿して、動作を確認すること
-->

## <a name="history">履歴</a>
#### ver1.6.20 (2025/11/27)
- **&lt;PARAM NAME="neo_enable_zoom_out" VALUE="true">**
このフラグを true にするとズームで、0.5倍、0.2倍に縮小表示できるようになります。
オリジナルのPaintBBSには無い機能なので**デフォルトは false です**。

#### ver1.6.19 (2025/10/11)
- `2chan.net`ではない別サイト(例 `example2chan.net`など)の時にふたば専用モードになる問題を修正しました。
#### ver1.6.18 (2025/06/08)
Expand Down
152 changes: 102 additions & 50 deletions dist/neo.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ document.addEventListener("DOMContentLoaded", function () {

var Neo = function () {};

Neo.version = "1.6.19";
Neo.version = "1.6.20";
Neo.painter;
Neo.fullScreen = false;
Neo.uploaded = false;
Expand Down Expand Up @@ -1109,8 +1109,20 @@ Neo.resizeCanvas = function () {
Neo.painter.destCanvasCtx = Neo.painter.destCanvas.getContext("2d", {
willReadFrequently: true,
});
Neo.painter.destCanvasCtx.imageSmoothingEnabled = false;
//Neo.painter.destCanvasCtx.mozImageSmoothingEnabled = false;

const ctx = Neo.painter.destCanvasCtx;
if (Neo.painter.zoom < 1) {
// 表示用アンチエイリアスを有効化
ctx.imageSmoothingEnabled = true;
Neo.painter.destCanvas.style.imageRendering = "smooth";
// 品質を指定(対応ブラウザのみ有効)
if ("imageSmoothingQuality" in ctx) {
ctx.imageSmoothingQuality = "high";
}
} else {
ctx.imageSmoothingEnabled = false;
Neo.painter.destCanvas.style.imageRendering = "pixelated";
}

Neo.canvas.style.width = width + "px";
Neo.canvas.style.height = height + "px";
Expand All @@ -1129,7 +1141,7 @@ Neo.resizeCanvas = function () {
}

Neo.painter.setZoom(Neo.painter.zoom);
Neo.painter.updateDestCanvas(0, 0, canvasWidth, canvasHeight);
Neo.painter.updateDestCanvas(0, 0, canvasWidth, canvasHeight, false);
};

/*
Expand Down Expand Up @@ -2073,7 +2085,6 @@ Neo.Painter.prototype._initCanvas = function (div, width, height) {

this.canvas[i].style.imageRendering = "pixelated";
this.canvasCtx[i].imageSmoothingEnabled = false;
this.canvasCtx[i].mozImageSmoothingEnabled = false;
this.visible[i] = true;
}

Expand Down Expand Up @@ -2102,7 +2113,6 @@ Neo.Painter.prototype._initCanvas = function (div, width, height) {

this.destCanvas.style.imageRendering = "pixelated";
this.destCanvasCtx.imageSmoothingEnabled = false;
this.destCanvasCtx.mozImageSmoothingEnabled = false;

var ref = this;

Expand Down Expand Up @@ -2500,7 +2510,7 @@ Neo.Painter.prototype._updateMousePosition = function (e) {
this.prevMouseX = this.mouseX;
}
if (isNaN(this.prevMouseY)) {
this.prevMosueY = this.mouseY;
this.prevMouseY = this.mouseY;
}

/*
Expand Down Expand Up @@ -2688,11 +2698,17 @@ Neo.Painter.prototype.setZoom = function (value) {
this.zoom = value;

var container = document.getElementById("container");
var width = this.canvasWidth * this.zoom;
var height = this.canvasHeight * this.zoom;
var width = Math.round(this.canvasWidth * this.zoom);
var height = Math.round(this.canvasHeight * this.zoom);

if (width > container.clientWidth - 100) width = container.clientWidth - 100;
if (height > container.clientHeight - 130)
height = container.clientHeight - 130;

// width, heightは偶数でないと誤差が出るため
width = Math.floor(width / 2) * 2;
height = Math.floor(height / 2) * 2;

this.destWidth = width;
this.destHeight = height;

Expand Down Expand Up @@ -2926,62 +2942,70 @@ Neo.Painter.prototype.updateDestCanvas = function (
height,
useTemp,
) {
// 元座標は整数化(元キャンバス側)
x = Math.floor(x);
y = Math.floor(y);

var canvasWidth = this.canvasWidth;
var canvasHeight = this.canvasHeight;
var updateAll = false;
if (x == 0 && y == 0 && width == canvasWidth && height == canvasHeight) {
updateAll = true;
}

if (x + width > this.canvasWidth) width = this.canvasWidth - x;
if (y + height > this.canvasHeight) height = this.canvasHeight - y;
var updateAll =
x === 0 && y === 0 && width === canvasWidth && height === canvasHeight;
if (x + width > canvasWidth) width = canvasWidth - x;
if (y + height > canvasHeight) height = canvasHeight - y;
if (x < 0) x = 0;
if (y < 0) y = 0;
if (width <= 0 || height <= 0) return;

var ctx = this.destCanvasCtx;
ctx.save();
ctx.fillStyle = "#ffffff";
ctx.globalAlpha = 1.0;

const zoom = this.zoom;
// ---- 描画先座標(拡大/縮小後のキャンバス側) ----
// scrollBarX/Y は 0~1 の比率
this.scrollBarX = isNaN(this.scrollBarX) ? 0 : this.scrollBarX;
this.scrollBarY = isNaN(this.scrollBarY) ? 0 : this.scrollBarY;
const offsetX =
this.scrollBarX * (this.canvasWidth * zoom - this.destCanvas.width);
const offsetY =
this.scrollBarY * (this.canvasHeight * zoom - this.destCanvas.height);

const zx = Math.round(x * zoom - offsetX);
const zy = Math.round(y * zoom - offsetY);

const zx2 = Math.round((x + width) * zoom - offsetX);
const zy2 = Math.round((y + height) * zoom - offsetY);

var fillWidth = width;
var fillHeight = height;
const zw = zx2 - zx;
const zh = zy2 - zy;

// ---- 背景クリア ----
if (updateAll) {
ctx.fillRect(0, 0, this.destCanvas.width, this.destCanvas.height);
} else {
//カーソルの描画ゴミが残るのをごまかすため
if (x + width == this.canvasWidth) fillWidth = width + 1;
if (y + height == this.canvasHeight) fillHeight = height + 1;
ctx.fillRect(zx, zy, zw, zh);
}

ctx.translate(this.destCanvas.width * 0.5, this.destCanvas.height * 0.5);
ctx.scale(this.zoom, this.zoom);
ctx.translate(-this.zoomX, -this.zoomY);
ctx.globalAlpha = 1.0;
ctx.msImageSmoothingEnabled = 0;

if (!updateAll) {
ctx.fillRect(x, y, fillWidth, fillHeight);
}
// ---- レイヤー描画 ----
if (this.visible[0])
ctx.drawImage(this.canvas[0], x, y, width, height, zx, zy, zw, zh);
if (this.visible[1])
ctx.drawImage(this.canvas[1], x, y, width, height, zx, zy, zw, zh);

if (this.visible[0]) {
ctx.drawImage(this.canvas[0], x, y, width, height, x, y, width, height);
}
if (this.visible[1]) {
ctx.drawImage(this.canvas[1], x, y, width, height, x, y, width, height);
}
// ---- テンポラリレイヤー ----
if (useTemp) {
ctx.globalAlpha = 1.0; //this.alpha;
const tempX = Math.floor(this.tempX * zoom);
const tempY = Math.floor(this.tempY * zoom);
ctx.drawImage(
this.tempCanvas,
x,
y,
width,
height,
x + this.tempX,
y + this.tempY,
width,
height,
zx + tempX,
zy + tempY,
zw,
zh,
);
}
ctx.restore();
Expand Down Expand Up @@ -3593,6 +3617,11 @@ Neo.Painter.prototype.drawBezier = function (

Neo.Painter.prototype.prevLine = null; // 始点または終点が2度プロットされることがあるので
Neo.Painter.prototype.drawLine = function (ctx, x0, y0, x1, y1, type) {
x0 = Math.floor(x0);
y0 = Math.floor(y0);
x1 = Math.floor(x1);
y1 = Math.floor(y1);

var points = [
[x0, y0],
[x1, y1],
Expand Down Expand Up @@ -4169,7 +4198,6 @@ Neo.Painter.prototype.doFloodFill = function (layer, x, y, fillColor) {
if ((baseColor & 0xff000000) == 0 || baseColor != fillColor) {
while (stack.length > 0) {
if (stack.length > 1000000) {
console.log("too much stack");
break;
}
var point = stack.pop();
Expand Down Expand Up @@ -4420,6 +4448,8 @@ Neo.Painter.prototype.getDestCanvasPosition = function (
mx += 0.499;
my += 0.499;
}

// マウス座標(描画先キャンバス座標)を計算
var x =
(mx - this.zoomX + (this.destCanvas.width * 0.5) / this.zoom) * this.zoom;
var y =
Expand Down Expand Up @@ -4966,8 +4996,10 @@ Neo.DrawToolBase.prototype.freeHandUpHandler = function (oe) {
oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true);
oe.cursorRect = null;
}

// oe.updateDestCanvas(0,0,oe.canvasWidth, oe.canvasHeight, true);
if (oe.zoom < 1) {
//縮小時はポインターアップで全体更新
oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
}
// this.drawCursor(oe);
oe.prevLine = null;
};
Expand Down Expand Up @@ -5003,13 +5035,23 @@ Neo.DrawToolBase.prototype.freeHandUpMoveHandler = function (oe) {
oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true);
oe.cursorRect = null;
}
//縮小時は浮動円カーソルを非表示 部分更新のグリッチが出るため
if (oe.zoom < 1) {
return;
}
//円カーソルを表示
this.drawCursor(oe);
};

Neo.DrawToolBase.prototype.drawCursor = function (oe) {
if (oe.zoom < 0.5) {
//0.2倍時にカーソルのゴミが出るため
return;
}
// if (oe.lineWidth <= 8) return;
var mx = oe.mouseX;
var my = oe.mouseY;
var mx = Math.floor(oe.mouseX);
var my = Math.floor(oe.mouseY);

var d = oe.lineWidth;
d = d == 1 ? 2 : d; //1pxの時は2px相当の円カーソルを表示

Expand Down Expand Up @@ -6130,11 +6172,16 @@ Neo.ZoomPlusCommand = function (data) {
};
Neo.ZoomPlusCommand.prototype = new Neo.CommandBase();
Neo.ZoomPlusCommand.prototype.execute = function () {
if (this.data.zoom < 12) {
if (this.data.zoom === 0.5 && Neo.config.neo_enable_zoom_out) {
this.data.setZoom(1);
} else if (this.data.zoom === 0.2 && Neo.config.neo_enable_zoom_out) {
this.data.setZoom(0.5);
} else if (this.data.zoom < 12) {
this.data.setZoom(this.data.zoom + 1);
}
Neo.resizeCanvas();
Neo.painter.updateDestCanvas();
// Neo.resizeCanvas()でupdateDestCanvas()を引数付きで呼び出しているためコメントアウト
// Neo.painter.updateDestCanvas();
};

Neo.ZoomMinusCommand = function (data) {
Expand All @@ -6144,9 +6191,14 @@ Neo.ZoomMinusCommand.prototype = new Neo.CommandBase();
Neo.ZoomMinusCommand.prototype.execute = function () {
if (this.data.zoom >= 2) {
this.data.setZoom(this.data.zoom - 1);
} else if (this.data.zoom === 1 && Neo.config.neo_enable_zoom_out) {
this.data.setZoom(0.5);
} else if (this.data.zoom === 0.5 && Neo.config.neo_enable_zoom_out) {
this.data.setZoom(0.2);
}
Neo.resizeCanvas();
Neo.painter.updateDestCanvas();
// Neo.resizeCanvas()でupdateDestCanvas()を引数付きで呼び出しているためコメントアウト
// Neo.painter.updateDestCanvas();
};

/*
Expand Down
Loading
Loading