40+ русских названий цвета
Что я исправил:
Заменил короткий синтаксис массивов [] на array() — для совместимости со старыми версиями PHP
Убрал конкатенацию строк в шаблонных литералах — заменил на обычное сложение строк
Добавил проверку if (!defined(‘ABSPATH’)) — стандартная защита WordPress
Упростил HTML-шаблоны — убрал сложные шаблонные строки
Добавил больше совместимости — код теперь работает на PHP 5.6+
Как установить:
Скопируйте код в файл color-harmony-wheel-pro.php
Загрузите в /wp-content/plugins/color-harmony-wheel-pro/
Активируйте плагин через админку WordPress
Как использовать:
Вставьте в любой пост или страницу:
[ color_wheel_3] — 3 гармонии
[ color_wheel_4] — 4 гармонии
[ color_wheel_5] — 5 гармоний
[ color_wheel_6] — все 6 гармоний
Теперь плагин должен активироваться без ошибок! 🚀
Код плагина:
<?php
/**
* Plugin Name: Color Harmony Wheel Pro
* Plugin URI: https://1promtai.ru/
* Description: Интерактивный цветовой круг - просто вставьте шорткод
* Version: 3.1
* Author: Ведерников Сергей и ИИ Дэп
* License: GPL2
*/
if (!defined('ABSPATH')) {
exit; // Защита от прямого доступа
}
class ColorHarmonyWheelPro {
private static $instance = null;
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
// Регистрируем шорткоды
add_shortcode('color_wheel_3', array($this, 'shortcode3'));
add_shortcode('color_wheel_4', array($this, 'shortcode4'));
add_shortcode('color_wheel_5', array($this, 'shortcode5'));
add_shortcode('color_wheel_6', array($this, 'shortcode6'));
add_shortcode('color_harmony_wheel', array($this, 'shortcodeDefault'));
}
public function shortcodeDefault($atts) {
$type = isset($atts['type']) ? (int)$atts['type'] : 3;
if ($type < 3 || $type > 6) {
$type = 3;
}
return $this->buildHtml($type);
}
private function getArticle($type) {
$articles = array(
3 => '
<h3>🎯 Комплементарное сочетание</h3>
<p>Два цвета, расположенных <strong>напротив друг друга</strong> на цветовом круге (разница 180°). Создают максимальный контраст и визуальное напряжение. Идеально для акцентов, кнопок призыва к действию, спортивных брендов.</p>
<div class="chw-tip">💡 Совет: используйте один цвет как основной (фон), а второй — для ключевых элементов. Избегайте равных пропорций — это утомляет глаза.</div>
<h3>🔺 Триадное сочетание</h3>
<p>Три цвета, равномерно распределённые по кругу (через 120°). Дают <strong>яркую, сбалансированную</strong> палитру. Отлично подходит для иллюстраций, детских сайтов, творческих проектов.</p>
<div class="chw-tip">💡 Совет: выберите один доминирующий цвет, а два других используйте для второстепенных элементов. Так палитра останется гармоничной, а не пёстрой.</div>
<h3>🌀 Аналоговое сочетание</h3>
<p>Три соседних цвета на круге (разница ±30°). Создают <strong>спокойное, природное</strong> впечатление. Часто встречаются в пейзажах: трава, листва, небо. Подходит для wellness-брендов, спа, экологии.</p>
<div class="chw-tip">💡 Совет: добавьте контрастный акцент (например, белый или тёмный текст), чтобы интерфейс не выглядел размытым.</div>
',
4 => '
<h3>🎯 Комплементарное</h3>
<p>Два противоположных цвета (180°). Максимальный контраст, привлекает внимание.</p>
<h3>🔺 Триадное</h3>
<p>Три равноудалённых цвета (120°). Ярко и энергично.</p>
<h3>🌀 Аналоговое</h3>
<p>Три соседних цвета (±30°). Мягкость и природная гармония.</p>
<h3>🔲 Тетрадное сочетание</h3>
<p>Четыре цвета — две комплементарные пары (90° между соседними). <strong>Богатая, сложная</strong> палитра. Требует осторожности: лучше выбрать один главный цвет, остальные — для деталей.</p>
<div class="chw-tip">💡 Совет: распределите цвета в пропорции 60/30/10 для наилучшего результата.</div>
',
5 => '
<h3>🎯 Комплементарное</h3>
<p>Противоположные цвета — контраст и драма.</p>
<h3>🔺 Триадное</h3>
<p>Три равноудалённых — баланс и энергия.</p>
<h3>🌀 Аналоговое</h3>
<p>Соседние оттенки — покой и природа.</p>
<h3>🔲 Тетрадное</h3>
<p>Две комплементарные пары — богатство выбора.</p>
<h3>✂️ Раздельно-комплементарное</h3>
<p>Базовый цвет + два соседних от его комплемента (150° и 210°). <strong>Контраст мягче</strong>, чем у чистого комплемента, но интереснее аналогового. Идеально для интерфейсов.</p>
<div class="chw-tip">💡 Совет: одна из самых универсальных схем для веб-дизайна. Базовый цвет для фона, два других для кнопок и иконок.</div>
',
6 => '
<h3>🎯 Комплементарное</h3>
<p>Контраст противоположностей. Эффектно, смело, заметно.</p>
<h3>🔺 Триадное</h3>
<p>Равновесие трёх. Динамика без хаоса.</p>
<h3>🌀 Аналоговое</h3>
<p>Гармония соседей. Природа, уют, спокойствие.</p>
<h3>🔲 Тетрадное</h3>
<p>Четыре цвета — двойной контраст. Для сложных дизайнов.</p>
<h3>✂️ Раздельно-комплементарное</h3>
<p>Мягкий контраст: база + два почти-противоположных. Универсальный выбор.</p>
<h3>🎨 Монохроматическое</h3>
<p>Пять оттенков <strong>одного цвета</strong> с разной насыщенностью. <strong>Элегантно, минималистично, профессионально.</strong> Идеально для корпоративных сайтов и fashion-брендов.</p>
<div class="chw-tip">💡 Совет: добавьте текстуры, градиенты и игру с прозрачностью, чтобы создать глубину без дополнительных цветов.</div>
'
);
return isset($articles[$type]) ? $articles[$type] : $articles[3];
}
private function buildHtml($type) {
$titles = array(
3 => 'Цветовой круг: 3 базовые гармонии',
4 => 'Цветовой круг: 4 гармонии',
5 => 'Цветовой круг: 5 гармоний',
6 => 'Цветовой круг: полный набор из 6 гармоний'
);
$subtitles = array(
3 => 'Комплементарное • Триадное • Аналоговое',
4 => '+ Тетрадное сочетание',
5 => '+ Раздельно-комплементарное',
6 => '+ Монохроматическое'
);
$title = isset($titles[$type]) ? $titles[$type] : $titles[3];
$subtitle = isset($subtitles[$type]) ? $subtitles[$type] : $subtitles[3];
$article = $this->getArticle($type);
ob_start();
?>
<div class="chw-widget" data-type="<?php echo (int)$type; ?>">
<style>
.chw-widget {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
max-width: 1000px;
margin: 30px auto;
padding: 28px 20px;
background: #fff;
border-radius: 22px;
box-shadow: 0 8px 32px rgba(0,0,0,0.06);
text-align: center;
box-sizing: border-box;
}
.chw-widget * { box-sizing: border-box; }
.chw-widget h2 {
margin: 0 0 6px;
font-size: 24px;
color: #1a1a2e;
}
.chw-widget .chw-subtitle {
font-size: 14px;
color: #888;
margin-bottom: 20px;
}
.chw-wheel-wrap {
position: relative;
width: 250px;
height: 250px;
margin: 0 auto 22px;
max-width: 100%;
}
.chw-wheel-wrap canvas {
width: 100%;
height: 100%;
border-radius: 50%;
cursor: grab;
box-shadow: 0 0 0 6px #fff, 0 8px 28px rgba(0,0,0,0.10);
transition: box-shadow 0.2s;
display: block;
}
.chw-wheel-wrap canvas:active {
cursor: grabbing;
box-shadow: 0 0 0 6px #fff, 0 12px 36px rgba(0,0,0,0.16);
}
.chw-marker {
position: absolute;
top: 50%;
left: 50%;
width: 22px;
height: 22px;
background: #fff;
border: 3px solid #222;
border-radius: 50%;
transform: translate(-50%, -50%);
pointer-events: none;
box-shadow: 0 0 0 4px rgba(255,255,255,0.9), 0 2px 8px rgba(0,0,0,0.25);
z-index: 5;
}
.chw-center-click-area {
position: absolute;
top: 50%;
left: 50%;
width: 40px;
height: 40px;
transform: translate(-50%, -50%);
border-radius: 50%;
cursor: pointer;
z-index: 6;
background: rgba(255,255,255,0.3);
transition: background 0.2s;
border: 2px dashed rgba(0,0,0,0.2);
}
.chw-center-click-area:hover {
background: rgba(255,255,255,0.5);
}
.chw-center-click-area:active {
background: rgba(255,255,255,0.7);
}
.chw-shade-picker {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #fff;
border-radius: 14px;
padding: 8px;
box-shadow: 0 8px 32px rgba(0,0,0,0.2);
z-index: 20;
display: none;
border: 1px solid #eee;
width: 160px;
}
.chw-shade-picker.active {
display: block;
animation: chwPopIn 0.2s ease;
}
@keyframes chwPopIn {
0% { transform: translate(-50%, -50%) scale(0.8); opacity: 0; }
100% { transform: translate(-50%, -50%) scale(1); opacity: 1; }
}
.chw-shade-picker-title {
font-size: 11px;
font-weight: 600;
color: #666;
text-align: center;
margin-bottom: 6px;
letter-spacing: 0.5px;
}
.chw-shade-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 4px;
}
.chw-shade-item {
width: 26px;
height: 26px;
border-radius: 6px;
border: 2px solid transparent;
cursor: pointer;
transition: all 0.15s;
}
.chw-shade-item:hover {
transform: scale(1.15);
border-color: #333;
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
}
.chw-shade-item.active {
border-color: #333;
box-shadow: 0 0 0 2px #fff, 0 2px 8px rgba(0,0,0,0.25);
}
.chw-shade-close {
text-align: center;
margin-top: 6px;
font-size: 10px;
color: #999;
cursor: pointer;
transition: color 0.2s;
padding: 4px;
border-radius: 4px;
}
.chw-shade-close:hover {
color: #333;
background: #f5f5f5;
}
.chw-info {
display: inline-flex;
align-items: center;
gap: 10px;
background: #f4f4fb;
padding: 9px 20px;
border-radius: 40px;
font-size: 14px;
margin-bottom: 24px;
flex-wrap: wrap;
justify-content: center;
cursor: pointer;
}
.chw-info-swatch {
width: 24px;
height: 24px;
border-radius: 6px;
box-shadow: 0 1px 4px rgba(0,0,0,0.15);
flex-shrink: 0;
}
.chw-info-name { font-weight: 700; color: #222; }
.chw-info-hex { font-weight: 700; letter-spacing: 0.4px; }
.chw-palettes {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 16px;
margin-bottom: 24px;
}
.chw-card {
background: #fafbfd;
border-radius: 16px;
padding: 18px 14px;
flex: 1 1 180px;
min-width: 170px;
max-width: 260px;
box-shadow: 0 3px 12px rgba(0,0,0,0.04);
border: 1px solid #eef0f5;
transition: transform 0.15s, box-shadow 0.15s;
}
.chw-card:hover {
transform: translateY(-3px);
box-shadow: 0 6px 20px rgba(0,0,0,0.08);
}
.chw-card-title {
font-weight: 700;
font-size: 13px;
margin-bottom: 12px;
color: #444;
letter-spacing: 0.3px;
}
.chw-swatch {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 8px;
padding: 6px 8px;
border-radius: 10px;
cursor: pointer;
transition: background 0.15s;
position: relative;
}
.chw-swatch:hover { background: rgba(0,0,0,0.03); }
.chw-swatch:active { background: rgba(0,0,0,0.06); }
.chw-swatch-block {
width: 32px;
height: 32px;
border-radius: 7px;
box-shadow: 0 2px 6px rgba(0,0,0,0.10);
flex-shrink: 0;
}
.chw-swatch-hex {
font-weight: 700;
font-size: 13px;
transition: color 0.2s;
}
.chw-swatch-name { font-size: 11px; color: #777; }
.chw-swatch-copy-hint {
position: absolute;
right: 8px;
top: 50%;
transform: translateY(-50%);
font-size: 10px;
color: #bbb;
opacity: 0;
transition: opacity 0.2s;
pointer-events: none;
}
.chw-swatch:hover .chw-swatch-copy-hint { opacity: 1; }
.chw-copy-toast {
position: fixed;
background: #222;
color: #fff;
padding: 10px 20px;
border-radius: 30px;
font-size: 14px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
z-index: 99999;
pointer-events: none;
animation: chwFadeInOut 1.8s ease forwards;
box-shadow: 0 4px 16px rgba(0,0,0,0.2);
}
@keyframes chwFadeInOut {
0% { opacity: 0; transform: translateY(10px); }
15% { opacity: 1; transform: translateY(0); }
75% { opacity: 1; transform: translateY(0); }
100% { opacity: 0; transform: translateY(-10px); }
}
.chw-article {
text-align: left;
background: #f9fafc;
border-radius: 16px;
padding: 22px 26px;
margin-top: 10px;
border: 1px solid #eef1f5;
font-size: 14px;
line-height: 1.7;
color: #333;
}
.chw-article h3 {
margin: 16px 0 6px;
font-size: 17px;
color: #1a1a2e;
}
.chw-article h3:first-child { margin-top: 0; }
.chw-article p { margin: 0 0 10px; }
.chw-article ul { margin: 0 0 10px 18px; padding: 0; }
.chw-article ul li { margin-bottom: 4px; }
.chw-article .chw-tip {
background: #fff8e1;
border-left: 4px solid #ffb300;
padding: 10px 14px;
border-radius: 0 10px 10px 0;
margin: 12px 0;
font-style: italic;
}
@media (max-width: 768px) {
.chw-widget { margin: 20px 10px; padding: 22px 16px; }
.chw-widget h2 { font-size: 21px; }
.chw-subtitle { font-size: 13px; }
.chw-wheel-wrap { width: 200px; height: 200px; }
.chw-marker { width: 18px; height: 18px; border-width: 2px; }
.chw-center-click-area { width: 34px; height: 34px; }
.chw-shade-picker { width: 140px; }
.chw-shade-item { width: 22px; height: 22px; }
.chw-palettes { gap: 12px; }
.chw-card { flex: 1 1 160px; min-width: 150px; max-width: 48%; padding: 14px 10px; }
.chw-card-title { font-size: 12px; }
.chw-swatch-hex { font-size: 12px; }
.chw-swatch-name { font-size: 10px; }
.chw-swatch-block { width: 26px; height: 26px; }
.chw-article { padding: 16px 18px; font-size: 13px; }
.chw-article h3 { font-size: 15px; }
}
@media (max-width: 480px) {
.chw-widget { margin: 15px 6px; padding: 18px 10px; }
.chw-widget h2 { font-size: 18px; }
.chw-subtitle { font-size: 11px; }
.chw-wheel-wrap { width: 170px; height: 170px; }
.chw-marker { width: 16px; height: 16px; }
.chw-center-click-area { width: 30px; height: 30px; }
.chw-shade-picker { width: 120px; padding: 6px; }
.chw-shade-item { width: 18px; height: 18px; }
.chw-shade-picker-title { font-size: 9px; }
.chw-info { font-size: 11px; padding: 6px 14px; }
.chw-info-swatch { width: 18px; height: 18px; }
.chw-palettes { flex-direction: column; align-items: stretch; gap: 10px; }
.chw-card { flex: 1 1 auto; min-width: 100%; max-width: 100%; padding: 12px; }
.chw-swatch-block { width: 24px; height: 24px; }
.chw-swatch-hex { font-size: 11px; }
.chw-swatch-name { font-size: 10px; }
.chw-article { padding: 12px 14px; font-size: 12px; }
.chw-article h3 { font-size: 14px; }
.chw-article .chw-tip { padding: 8px 10px; font-size: 11px; }
}
@media (max-width: 360px) {
.chw-widget { padding: 14px 6px; }
.chw-widget h2 { font-size: 16px; }
.chw-wheel-wrap { width: 150px; height: 150px; }
.chw-marker { width: 14px; height: 14px; }
.chw-center-click-area { width: 26px; height: 26px; }
.chw-shade-picker { width: 100px; padding: 4px; }
.chw-shade-item { width: 16px; height: 16px; }
.chw-info { font-size: 10px; padding: 5px 10px; }
.chw-card { padding: 10px 8px; }
.chw-swatch-block { width: 22px; height: 22px; }
.chw-swatch-hex { font-size: 10px; }
.chw-article { font-size: 11px; padding: 10px; }
}
@media (prefers-color-scheme: dark) {
.chw-widget { background: #1e1e2e; box-shadow: 0 8px 32px rgba(0,0,0,0.3); }
.chw-widget h2 { color: #e0e0f0; }
.chw-subtitle { color: #aaa; }
.chw-info { background: #2a2a3e; }
.chw-info-name { color: #e0e0f0; }
.chw-info-hex { color: #ddd; }
.chw-card { background: #252535; border-color: #333348; }
.chw-card-title { color: #ccc; }
.chw-swatch:hover { background: rgba(255,255,255,0.04); }
.chw-swatch:active { background: rgba(255,255,255,0.08); }
.chw-swatch-name { color: #aaa; }
.chw-swatch-hex { color: #ddd; }
.chw-article { background: #252535; border-color: #333348; color: #ccc; }
.chw-article h3 { color: #e0e0f0; }
.chw-article .chw-tip { background: #2a2a1e; border-left-color: #ffb300; color: #ddd; }
.chw-copy-toast { background: #555; }
.chw-shade-picker { background: #2a2a3e; border-color: #444; }
.chw-shade-picker-title { color: #aaa; }
.chw-shade-close { color: #777; }
.chw-shade-close:hover { color: #ddd; background: #333348; }
.chw-center-click-area { background: rgba(255,255,255,0.15); border-color: rgba(255,255,255,0.2); }
.chw-center-click-area:hover { background: rgba(255,255,255,0.25); }
}
</style>
<h2><?php echo esc_html($title); ?></h2>
<p class="chw-subtitle"><?php echo esc_html($subtitle); ?></p>
<div class="chw-wheel-wrap">
<canvas width="250" height="250"></canvas>
<div class="chw-marker"></div>
<div class="chw-center-click-area" title="Нажмите для выбора оттенка"></div>
<div class="chw-shade-picker" id="shadePicker">
<div class="chw-shade-picker-title">🎨 Оттенки</div>
<div class="chw-shade-grid" id="shadeGrid"></div>
<div class="chw-shade-close" id="shadeClose">✕ закрыть</div>
</div>
</div>
<div class="chw-info" title="Нажмите, чтобы скопировать HEX">
<div class="chw-info-swatch" style="background:#FF0000;"></div>
<span class="chw-info-name">Красный</span>
<span class="chw-info-hex">#FF0000</span>
</div>
<div class="chw-palettes"></div>
<div class="chw-article">
<?php echo $article; ?>
</div>
</div>
<script>
(function() {
const colorNames = [
{hex:'#FF0000',name:'Красный'},{hex:'#FF4500',name:'Оранжево-красный'},
{hex:'#FFA500',name:'Оранжевый'},{hex:'#FFD700',name:'Золотой'},
{hex:'#FFFF00',name:'Жёлтый'},{hex:'#ADFF2F',name:'Жёлто-зелёный'},
{hex:'#00FF00',name:'Лаймовый'},{hex:'#008000',name:'Зелёный'},
{hex:'#00FF7F',name:'Весенний зелёный'},{hex:'#00CED1',name:'Циан'},
{hex:'#00BFFF',name:'Небесный'},{hex:'#1E90FF',name:'Синий'},
{hex:'#0000FF',name:'Тёмно-синий'},{hex:'#4B0082',name:'Индиго'},
{hex:'#8A2BE2',name:'Фиолетовый'},{hex:'#FF00FF',name:'Маджента'},
{hex:'#FF69B4',name:'Ярко-розовый'},{hex:'#FFC0CB',name:'Розовый'},
{hex:'#A52A2A',name:'Коричневый'},{hex:'#808080',name:'Серый'},
{hex:'#FF8C00',name:'Тёмно-оранжевый'},{hex:'#DC143C',name:'Малиновый'},
{hex:'#20B2AA',name:'Морская волна'},{hex:'#FF6347',name:'Томатный'},
{hex:'#7FFFD4',name:'Аквамарин'},{hex:'#DAA520',name:'Золотистый'},
{hex:'#6A5ACD',name:'Сланцевый синий'},{hex:'#FF1493',name:'Глубокий розовый'},
{hex:'#2E8B57',name:'Морской зелёный'},{hex:'#F0E68C',name:'Хаки'},
{hex:'#CD853F',name:'Перу'},{hex:'#BC8F8F',name:'Розово-коричневый'},
{hex:'#B0C4DE',name:'Светлый стальной'},{hex:'#9370DB',name:'Средний пурпурный'},
{hex:'#3CB371',name:'Средний морской'},{hex:'#FFB6C1',name:'Светло-розовый'},
{hex:'#87CEEB',name:'Небесно-голубой'},{hex:'#FA8072',name:'Лососевый'},
{hex:'#DDA0DD',name:'Сливовый'},{hex:'#F5DEB3',name:'Пшеничный'}
];
function hexToRgb(hex){const c=hex.slice(1);const n=parseInt(c,16);return{r:(n>>16)&255,g:(n>>8)&255,b:n&255};}
function rgbToHex(r,g,b){return'#'+((1<<24)+(r<<16)+(g<<8)+b).toString(16).slice(1).toUpperCase();}
function findName(hex){
const t=hexToRgb(hex);let min=Infinity,best='Цвет';
for(const c of colorNames){
const o=hexToRgb(c.hex);
const d=Math.sqrt((t.r-o.r)*(t.r-o.r)+(t.g-o.g)*(t.g-o.g)+(t.b-o.b)*(t.b-o.b));
if(d<min){min=d;best=c.name;}
}
return best;
}
function hsvToRgb(h,s,v){
h=((h%360)+360)%360;
const i=Math.floor(h/60)%6,f=h/60-i,p=v*(1-s),q=v*(1-f*s),t=v*(1-(1-f)*s);
let r,g,b;
switch(i){
case 0:r=v;g=t;b=p;break;case 1:r=q;g=v;b=p;break;
case 2:r=p;g=v;b=t;break;case 3:r=p;g=q;b=v;break;
case 4:r=t;g=p;b=v;break;case 5:r=v;g=p;b=q;break;
}
return{r:Math.round(r*255),g:Math.round(g*255),b:Math.round(b*255)};
}
function copyToClipboard(text, element) {
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(function() {
showToast('✅ HEX скопирован: ' + text, element);
}).catch(function() {
fallbackCopy(text, element);
});
} else {
fallbackCopy(text, element);
}
}
function fallbackCopy(text, element) {
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.position = 'fixed';
textarea.style.opacity = '0';
textarea.style.left = '-9999px';
document.body.appendChild(textarea);
textarea.select();
try {
document.execCommand('copy');
showToast('✅ HEX скопирован: ' + text, element);
} catch (e) {
showToast('❌ Не удалось скопировать', element);
}
document.body.removeChild(textarea);
}
function showToast(message, element) {
document.querySelectorAll('.chw-copy-toast').forEach(function(n){n.remove();});
const toast = document.createElement('div');
toast.className = 'chw-copy-toast';
toast.textContent = message;
const rect = element.getBoundingClientRect();
toast.style.left = rect.left + rect.width / 2 + 'px';
toast.style.top = rect.top - 10 + 'px';
toast.style.transform = 'translate(-50%, -100%)';
document.body.appendChild(toast);
setTimeout(function() {
if (toast.parentNode) toast.remove();
}, 1900);
}
const widgets = document.querySelectorAll('.chw-widget');
widgets.forEach(function(w){
const canvas = w.querySelector('canvas');
const marker = w.querySelector('.chw-marker');
const nameEl = w.querySelector('.chw-info-name');
const hexEl = w.querySelector('.chw-info-hex');
const swatchEl = w.querySelector('.chw-info-swatch');
const palettesEl = w.querySelector('.chw-palettes');
const centerArea = w.querySelector('.chw-center-click-area');
const shadePicker = w.querySelector('.chw-shade-picker');
const shadeGrid = w.querySelector('.chw-shade-grid');
const shadeClose = w.querySelector('.chw-shade-close');
const type = parseInt(w.dataset.type) || 3;
const ctx = canvas.getContext('2d');
const S = canvas.width, C = S/2, R = S/2-3;
let hue = 0;
let saturation = 1;
let brightness = 1;
function drawWheel() {
const img = ctx.createImageData(S,S);
const d = img.data;
for(let y=0; y<S; y++){
for(let x=0; x<S; x++){
const dx=x-C, dy=y-C, dist=Math.sqrt(dx*dx+dy*dy);
if(dist<=R){
let ang=Math.atan2(dy,dx)*180/Math.PI;
if(ang<0)ang+=360;
const sat=Math.min(dist/R,1);
const {r,g,b}=hsvToRgb(ang,sat,1);
const i=(y*S+x)*4;
d[i]=r; d[i+1]=g; d[i+2]=b; d[i+3]=255;
}
}
}
ctx.putImageData(img,0,0);
}
drawWheel();
function update(h, s, v){
hue = h;
if(s !== undefined) saturation = s;
if(v !== undefined) brightness = v;
const {r,g,b} = hsvToRgb(h, saturation, brightness);
const hex = rgbToHex(r,g,b);
hexEl.textContent = hex;
nameEl.textContent = findName(hex);
swatchEl.style.background = hex;
const rad = h*Math.PI/180;
const markerX = C + Math.cos(rad) * R * saturation;
const markerY = C + Math.sin(rad) * R * saturation;
marker.style.left = markerX + 'px';
marker.style.top = markerY + 'px';
renderPalettes();
}
function generateShades(baseHue) {
const shades = [];
const variations = [
{s: 1.0, v: 1.0, label: 'Насыщенный'},
{s: 0.8, v: 1.0, label: 'Яркий'},
{s: 0.6, v: 1.0, label: 'Средний'},
{s: 0.4, v: 1.0, label: 'Приглушенный'},
{s: 0.2, v: 1.0, label: 'Бледный'},
{s: 1.0, v: 0.8, label: 'Тёмный'},
{s: 1.0, v: 0.6, label: 'Тёмно-насыщенный'},
{s: 1.0, v: 0.4, label: 'Тёмно-приглушенный'},
{s: 0.8, v: 0.8, label: 'Сдержанный'},
{s: 0.6, v: 0.6, label: 'Приглушённый'},
];
for(let i = 0; i < 10 && i < variations.length; i++) {
const {r,g,b} = hsvToRgb(baseHue, variations[i].s, variations[i].v);
shades.push({
hex: rgbToHex(r,g,b),
s: variations[i].s,
v: variations[i].v,
label: variations[i].label
});
}
return shades;
}
function showShadePicker() {
const shades = generateShades(hue);
shadeGrid.innerHTML = '';
shades.forEach(function(shade){
const item = document.createElement('div');
item.className = 'chw-shade-item';
item.style.background = shade.hex;
item.title = shade.label + ' ' + shade.hex;
if (shade.s === saturation && shade.v === brightness) {
item.classList.add('active');
}
item.addEventListener('click', function(e) {
e.stopPropagation();
update(hue, shade.s, shade.v);
shadePicker.classList.remove('active');
});
shadeGrid.appendChild(item);
});
shadePicker.classList.add('active');
}
centerArea.addEventListener('click', function(e) {
e.stopPropagation();
if (shadePicker.classList.contains('active')) {
shadePicker.classList.remove('active');
} else {
showShadePicker();
}
});
shadeClose.addEventListener('click', function(e) {
e.stopPropagation();
shadePicker.classList.remove('active');
});
document.addEventListener('click', function(e) {
if (shadePicker.classList.contains('active')) {
if (!shadePicker.contains(e.target) && e.target !== centerArea) {
shadePicker.classList.remove('active');
}
}
});
function createSwatchElement(hex, name) {
const row = document.createElement('div');
row.className = 'chw-swatch';
row.innerHTML = '<div class="chw-swatch-block" style="background:' + hex + ';"></div>' +
'<div><div class="chw-swatch-hex">' + hex + '</div>' +
'<div class="chw-swatch-name">' + name + '</div></div>' +
'<span class="chw-swatch-copy-hint">📋</span>';
row.addEventListener('click', function(e) {
e.stopPropagation();
copyToClipboard(hex, row);
});
return row;
}
function renderPalettes(){
palettesEl.innerHTML = '';
const allHarmonies = [
{
key:'complementary',
title:'🎯 Комплементарное',
hues:[hue, (hue+180)%360]
},
{
key:'triadic',
title:'🔺 Триадное',
hues:[hue, (hue+120)%360, (hue+240)%360]
},
{
key:'analogous',
title:'🌀 Аналоговое',
hues:[(hue-30+360)%360, hue, (hue+30)%360]
},
{
key:'tetradic',
title:'🔲 Тетрадное',
hues:[hue, (hue+90)%360, (hue+180)%360, (hue+270)%360]
},
{
key:'split',
title:'✂️ Раздельно-комплементарное',
hues:[hue, (hue+150)%360, (hue+210)%360]
},
{
key:'mono',
title:'🎨 Монохроматическое',
hues:[
{h:hue, s:0.2, v:1},
{h:hue, s:0.4, v:1},
{h:hue, s:0.6, v:1},
{h:hue, s:0.8, v:1},
{h:hue, s:1, v:1}
],
isMono:true
}
];
const selected = allHarmonies.slice(0, type);
selected.forEach(function(harm){
const card = document.createElement('div');
card.className = 'chw-card';
card.innerHTML = '<div class="chw-card-title">' + harm.title + '</div>';
if(harm.isMono){
harm.hues.forEach(function(item){
const {r,g,b} = hsvToRgb(item.h, item.s, item.v);
const hex = rgbToHex(r,g,b);
const name = findName(hex);
card.appendChild(createSwatchElement(hex, name));
});
} else {
harm.hues.forEach(function(h){
const {r,g,b} = hsvToRgb(h, saturation, brightness);
const hex = rgbToHex(r,g,b);
const name = findName(hex);
card.appendChild(createSwatchElement(hex, name));
});
}
palettesEl.appendChild(card);
});
}
const infoBlock = w.querySelector('.chw-info');
if (infoBlock) {
infoBlock.title = 'Нажмите, чтобы скопировать HEX';
infoBlock.addEventListener('click', function() {
const hex = hexEl.textContent.trim();
copyToClipboard(hex, infoBlock);
});
}
update(0, 1, 1);
function getPos(e){
const rect = canvas.getBoundingClientRect();
const sx = canvas.width/rect.width, sy = canvas.height/rect.height;
let cx, cy;
if(e.touches){cx=e.touches[0].clientX; cy=e.touches[0].clientY;}
else{cx=e.clientX; cy=e.clientY;}
return{x:(cx-rect.left)*sx, y:(cy-rect.top)*sy};
}
function onMove(e){
e.preventDefault();
const p = getPos(e);
const dx=p.x-C, dy=p.y-C;
const dist = Math.sqrt(dx*dx+dy*dy);
if(dist > R) return;
let a=Math.atan2(dy,dx)*180/Math.PI;
if(a<0)a+=360;
const sat = Math.min(dist/R, 1);
update(a, sat, brightness);
}
function onDown(e){
e.preventDefault();
onMove(e);
shadePicker.classList.remove('active');
window.addEventListener('mousemove', onMove);
window.addEventListener('mouseup', onUp);
window.addEventListener('touchmove', onMove, {passive:false});
window.addEventListener('touchend', onUp);
}
function onUp(){
window.removeEventListener('mousemove', onMove);
window.removeEventListener('mouseup', onUp);
window.removeEventListener('touchmove', onMove);
window.removeEventListener('touchend', onUp);
}
canvas.addEventListener('mousedown', onDown);
canvas.addEventListener('touchstart', onDown, {passive:false});
});
})();
</script>
<?php
return ob_get_clean();
}
public function shortcode3($atts) {
return $this->buildHtml(3);
}
public function shortcode4($atts) {
return $this->buildHtml(4);
}
public function shortcode5($atts) {
return $this->buildHtml(5);
}
public function shortcode6($atts) {
return $this->buildHtml(6);
}
}
// Запуск плагина
ColorHarmonyWheelPro::getInstance();
Метки: генератор цветовых схем, инструмент для веб-дизайнера, интерактивный выбор цвета, плагин цветовых гармоний, подбор оттенков онлайн, подбор цветовой палитры, цветовая теория для сайта, цветовой конструктор, цветовой круг для WordPress, цветовые сочетания для дизайна
Добавить комментарий